DeepSeek Harness plugin load: already registered, pending
In DeepSeek Harness (DSH), "a plugin is installed but has no effect" is an especially time-consuming class of failure, because it often lacks three things at once: no error, no log, and no UI hint. This batch of discussions splits the family into six fixed shapes, whose common point is that the failure happens at the plugin activation (apply / register) stage, not when the plugin is called: a duplicate tool name makes the registry throw, the whole fiber is unloaded, and the error is only written to the log service while the factory profile has no log output attached, so it is completely silent; a plugin's declared service dependency crosses a realm, and the entry stays forever at pending (waiting for service: …); ctx.skills.register() does not fill in a default source, while the read side requires it to be a string, so a registered skill "appears in the list but fails to load"; on a config reload the file-upload resolver's reference comparison fails and throws already registered, after which no new session can be created; on a hot reload the dispose path cancels the turn and clears the inbox, silently dropping queued messages; and on Windows the npm-installed CLI can even fail silently at startup because of a process-level duplicate koffi type (#9308, #8968, #9425, #9550, #9711, #9843, #9553).
DeepSeek Harness duplicate tool registration: the plugin fails entirely, and completely silently
In one sentence: a duplicate registration makes the registry throw, a plugin's apply throwing unloads the whole fiber (all or nothing), and this error only goes to the log service — the factory profile has no log output attached and the desktop stderr stays only in an in-memory ring buffer, so "the market shows it enabled, not one tool can be called, the log has 0 hits". (#9308)
DeepSeek Harness three-step locate
- Confirm that "the tool and the system-prompt injection section disappear together": with only one plugin attached the thing that disappears may be one tool; with several similar plugins attached the whole batch may disappear. "The whole batch" is the key signal, because a single-point failure does not disappear in a batch (#9308).
- Force out the swallowed error: start the host from a terminal (not from a desktop icon), making stderr visible; expect to see a registration-time error such as
… is already registered(#9308). - Confirm the real cause with a diagnostic plugin: the community plugin
@argszero/dsh-activation-doctordetects activation failures and reports the reason (#9308):
npm i @argszero/dsh-activation-doctor
DeepSeek Harness handling
- Find the two plugins with the clashing name: disable suspicious plugins one by one and re-enable only one at a time, watching whether the tool comes back — bisection is faster than reading logs (#9308).
- Rename the tool in one of them, or keep only one.
- Verify: after reopening, confirm the tool and the injection section come back together before calling it really fixed — seeing only "the plugin is enabled" does not count (#9308).
DeepSeek Harness duplicate registration: Agent resolver is already registered
In one sentence: the register function compares references in the destroy callback, but the compared object is proxy-wrapped and every read returns a new wrapper, so the comparison is forever false and the destroy callback is dead code; the result is that every reload registers again, and after the throw a new session can never be created. The trigger is very broad — any rewrite of cordis.patch.yml (even a byte-identical rewrite) triggers a reload (#8968).
DeepSeek Harness four-step handling
- Confirm the criterion: the error text is
file-upload: Agent resolver is already registered, and the symptom is that a new session can never be created (existing sessions may still work); restarting the process recovers it (#8968). - Stopgap: restart the host process — the only means of immediate recovery (#8968).
- Do not feel reassured by "sequential dispose / rebuild looks normal": the thread stresses that this is only an illusion; the destroy callback does run, but the reference comparison always fails, so the registration is not revoked (#8968).
- Long-term avoidance: bind the registration identity to a plain object (a token) rather than a function, so the reference comparison holds; the community already has a tested patch (#8968).
DeepSeek Harness cross-realm service dependency: the entry stays pending forever
In one sentence: after a plugin declares inject: ['compaction'], the entry stays forever at pending (waiting for service: compaction), not because the service is not installed, but because the provider and the consumer are not in the same realm — the provider is in the agent preset's group and the plugin is at the profile layer, and cross-realm unreachability is by design. (#9425) Still, when an entry sits at pending and looks like "installed but no effect", it is worth confirming the install side actually finished first — cross-check DSH plugin install fails: add hangs and junction delete.
DeepSeek Harness three-step locate and handling
- Criterion 1: look at the command list, not the service. If
commands.list()contains the compact command (showing the backend is running) butctx.get('compaction')cannot get the service, it is a realm-boundary problem (#9425). - Criterion 2: watch the property-read trap. Reading
ctx.compactiondirectly sometimes returns a string rather thanundefined, easily making you misjudge "the service is there, just unusable". This is also why the channel's pending and disabled appearances differ while both behave as "the service does not exist" (#9425). - Handling 1 (recommended): switch to performing it through a command, rather than relying on service dependency injection:
// In the plugin, use the command channel instead of declaring an inject service
await ctx.commands.execute(agent, '/compact', [], signal)
- Handling 2: install the compaction backend at the same level as the plugin; the thread confirms that after moving the backend to the same layer
ctx.compactionis immediately available (#9425). - Verify: after reopening, confirm the entry is no longer
pendingandctx.get('compaction')can get the service object (#9425).
DeepSeek Harness plugin-registered skill fails to load: the write path lacks a default
In one sentence: ctx.skills.register() allows omitting source, but the runtime validation requires it to be a string — the shape the write path validates and the shape the read path requires are inconsistent, so "registration succeeds, load fails". The error is loaded skill "<name>" source must be a string (#9550).
- Confirm: the skill appears in the list, but the moment it is called it reports the above error, showing registration succeeded and loading failed (#9550).
- Plugin-side workaround (least trouble): pass
sourceexplicitly at registration:
ctx.skills.register({ name, description, content, invocation, source: 'runtime' })
- Verify: after reopening, call that skill and expect no more
source must be a string(#9550). - Two upstream fixes (pick one): give
sourcea default (for example'runtime'), or reject a call missingsourceat registration — making the validation happen at write time rather than read time is the root fix direction noted in the thread (#9550).
DeepSeek Harness hot reload drops queued messages: the event has a receipt, the UI does not subscribe
In one sentence: the hot reload's dispose path cancels the turn with {kind:'disposed'}, and the cancellation clears the inbox before aborting, so queued messages vanish silently; the event actually already emits a "dropped" receipt, only the UI does not subscribe to it, so it looks like you canceled it yourself. The trigger window is very specific: within about 2.8 seconds of changing dsh.profile.bundles or installing/uninstalling a plugin from the UI (#9711).
- Confirm the criterion: the turn is aborted, the queued messages disappear, and the event shows
outcome: "canceled"— the misleading wording is this point's typical feature (#9711). - Avoidance: do not change
bundles-related config or install/uninstall plugins while a turn is running; wait for the turn to end (#9711). - Minimal fix (core side): make the dispose path pass
keepInbox: truetoo — the path for a user-initiated stop already passes it, and the hot reload path missed it (#9711). - Verify: after a config reload, expect the queued messages to still be in the queue; if the UI still does not make it clear, note down "the event was emitted, the UI did not receive it" as a basis for judgment (#9711).
DeepSeek Harness two seemingly unrelated traps in the same family
DSH plugin these two failures share one family: both happen at the "plugin and host" interaction boundary — one treats a legitimate tab-close veto as an error and silently turns a neighboring plugin's openTab into a no-op, the other makes two copies of the same native module collide on the process-level type registry, and the common trait is that the error never points at the real cause.
DSH plugin legitimate close-handler veto logged as an error flood
In one sentence: a plugin using "throw to keep a tab open" is a documented veto channel, but the close path wraps it in try/catch { console.error(...) }, so every legitimate veto prints an error; worse, the replace branch of place() has no try/catch, so one plugin's veto silently turns another plugin's openTab into a no-op. (#9843)
- Confirm: the console shows "a legitimate close printing an error" noise, accompanied by another plugin failing to open a tab (#9843).
- Handling: separate a veto from a real failure — a veto should not be logged as an error; add a catch to the replace branch of
place()(#9843). - Note: changing the log level will change the test contract, so check the relevant tests before changing it (#9843).
DSH plugin CLI fails silently at startup on Windows
In one sentence: when the install tree has multiple copies of the same native module, the two are loaded one after the other, and the second collides on koffi's process-level type registry, so entry initialization fails and the whole plugin tree reports "unable to resolve", while the error carries no real exception. The error text is similar to plugin tree failed to load … could not be resolved (#9553).
- Confirm: check whether there are multiple copies of the same native module (common in an old environment built up by repeated installs) (#9553).
- Handling (most direct): clean up the redundant copies and reinstall; a freshly installed environment usually has only one copy and does not hit it (#9553).
- Dig out the real exception (reusable): attach a diagnostic plugin that in the load context calls the loader directly and
try/catchwrites a file, and you can get the swallowed original exception; you can also recover entry-level errors from the log service's output (#9553).
DSH plugin troubleshooting notes
The main line for this family is: first decide whether the failure happens at the "activation stage" or the "call stage" — an activation-stage failure appears as "installed but completely ineffective", while a call-stage failure has a concrete error. Nine points:
- "A whole batch of tools disappears together" is the fingerprint of an activation-stage failure, so do not investigate it as a single tool (#9308).
- Starting from a terminal shows the swallowed errors, and it is the lowest-cost step (#9308).
- "The market shows it enabled" is not evidence: it reflects install state, not activation state (#9308).
- For reload-class failures, restart first, then analyze: for the
already registeredkind, a restart is the only immediate recovery (#8968). - For
pending (waiting for service), look at the realm boundary first, then at whether the service is actually installed (#9425). - Property reads lie:
ctx.compactionmay return a string rather than undefined, so usectx.get()as the criterion (#9425). - A register interface should "validate on write": the skill's
sourceis a typical counterexample (#9550). - Do not install/uninstall plugins while a turn is running: the hot reload's 2.8-second window eats your queued messages (#9711).
- State the fix status honestly: the visibility of duplicate registration, the resolver reference comparison, realm reachability, the
sourcedefault, and the disposekeepInboxare all unfixed in the versions the discussions refer to; everything given here is user-side avoidance and community plugins, of which only "passsourceexplicitly", "rename / keep only one plugin", "restart the host", and "avoid changing config while running" are immediately executable.
The most time-consuming part of troubleshooting "installed but no effect" plugins is really confirming how much is loaded in the environment. Rather than typing commands in various places, use a visual plugin marketplace such as DSH Plugin Hub: the installed list carries source markers, and the install/uninstall history and system logs are collected in one panel, so first seeing "what is installed, when it was installed, and whether it errored" makes the actual work much faster.

Source: Discussion #9308, Discussion #8968, Discussion #9425, Discussion #9550, Discussion #9711, Discussion #9843, Discussion #9553.
FAQ
In DeepSeek Harness, a plugin shown as enabled but with no callable tools should make you suspect duplicate tool registration first. The registry throws already registered for a duplicate tool name, and a plugin throwing in the apply stage causes the whole fiber to be unloaded — all or nothing; worse, the error is only written to the log service, the factory profile has no log output attached, and the desktop stderr stays in an in-memory ring buffer, so it appears completely silent. A workable approach is to start the host from a terminal so stderr is visible, or use a diagnostic plugin that can detect activation failures.
In DeepSeek Harness the entry stays pending forever because that service and the plugin live in different realms. The compaction backend is inside the agent preset's group realm, while the plugin is an entry at the profile layer, and cross-realm unreachability is by design; the criterion is that commands.list() shows the compact command but ctx.get('compaction') cannot get the service. Workarounds are to perform compaction through a command, or install the compaction backend at the same level as the plugin.
In DeepSeek Harness a plugin-registered skill fails to load because the register interface does not fill in a default for source, while the runtime validation requires it to be a string — the write path and the read path have inconsistent shape requirements. The least-trouble plugin-side workaround is to pass source: 'runtime' explicitly; the root fix is to give the register interface a default, or reject the illegal shape at registration instead of deferring the error to load time.
In DeepSeek Harness the uncreatable new session is a duplicate registration caused by a failed reference comparison. The register function compares references in the destroy callback, but that side's service is proxy-wrapped and every property read on the function returns a new wrapper, so the comparison is forever false and the destroy callback is dead code. The workaround is to restart the host process; the long-term fix is to bind the registration identity to a plain object rather than a function, so the reference comparison holds.
In DeepSeek Harness the hot reload drops queued messages because the dispose path cancels the turn but clears the inbox. The event actually already carries a receipt for the dropped messages, only the UI does not subscribe to it, so it looks like the user canceled. The minimal fix is to pass keepInbox on the dispose path too, so queued messages are kept; until then, avoid changing bundles-related config while a turn is running.
Related Terms
- realm
- A realm is a scope boundary for service registration and resolution in DeepSeek Harness; a provider and a consumer can see each other only within the same realm. The agent preset's group and the profile layer belong to different realms, so a service registered inside a preset is by default unreachable from a profile-layer plugin.— https://github.com/deepseek-ai/deepseek-harness/discussions/9425
- fiber
- A fiber is a plugin-instance runtime unit in the cordis plugin system; a plugin's apply throwing causes the whole fiber to be unloaded, and its registered tools and system-prompt injection sections disappear with it, appearing as "the plugin is enabled but has no effect at all".— https://github.com/deepseek-ai/deepseek-harness/discussions/9308
- Agent resolver is already registered
- Agent resolver is already registered is the error the file-upload module throws when it registers the same resolver twice. It appears during the rebuilding of the session controller after a config reload, and once thrown, no new session can ever be created and only a host restart recovers it.— https://github.com/deepseek-ai/deepseek-harness/discussions/8968
- keepInbox
- keepInbox is an option when canceling a turn, deciding whether this cancellation keeps the not-yet-processed messages in the inbox. The hot reload's dispose path does not carry it by default, so queued messages are cleared along with the cancellation.— https://github.com/deepseek-ai/deepseek-harness/discussions/9711
Sources
- #9308 — When a plugin fails to register because of a duplicate tool name the user cannot perceive it at all: the market still shows it enabled, with no UI hint and no log at all· deepseek-ai (GitHub Discussions)
- #8968 — file-upload: Agent resolver is already registered — any cordis.patch.yml reload permanently kills sessionController· deepseek-ai (GitHub Discussions)
- #9425 — A plugin cannot reach the compaction service: after declaring inject the entry stays pending forever· deepseek-ai (GitHub Discussions)
- #9550 — ctx.skills.register() does not default source, so plugin-registered skills fail to load· deepseek-ai (GitHub Discussions)
- #9711 — When a turn is disposed (config hot reload) queued messages are silently dropped, and marking the event canceled misleads into thinking the user canceled· deepseek-ai (GitHub Discussions)
- #9843 — Legitimate close-handler veto is logged with console.error; the replaceTab path calls close handlers without a catch· deepseek-ai (GitHub Discussions)
- #9553 — dsh CLI on Windows: entry import failures — invisible on 0.1.5-rc.2, downgraded to a warning later· deepseek-ai (GitHub Discussions)