You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A faulty in-process third-party plugin can currently make unrelated tools appear to fail after they have already executed.
In the incident that prompted this discussion, @deepseek-ai/dsh-tool-indexed-search registered a global tools/post-execute listener intended to process locate results. The listener did not first check exec.name === 'locate', so it attempted to access value.results.length for results from unrelated tools such as read, pwsh, glob, skill, Cordis, and job_list. Those values do not necessarily have a results property, producing:
Cannot read properties of undefined (reading 'length')
This is directly a plugin bug, not a claim that DSH core tools are broken. However, it exposes a fault-isolation, diagnostics, and side-effect ambiguity gap at the trusted in-process post-execute extension point.
If it is registered globally and omits an exec.name === 'locate' guard, a non-locate result can cause the listener to throw.
Observed behavior
After the plugin was hot-mounted through its profile patch, the next read call immediately failed at tools/post-execute.
Subsequent calls to unrelated tools (including pwsh, glob, skill, job_list, and Cordis) all returned the same error; more than 20 calls were affected.
The harness itself remained alive. The exception was confined to an individual tool result, but the same failing global listener participated in every later call, making the tool surface effectively unavailable.
In packages/core/tools/src/index.ts, finalizeScheduledExecution / postExecute converts a throwing post-execute listener into an isError result. packages/core/tools/tests/tools.spec.ts explicitly tests this behavior.
The most concerning consequence is semantic: the tool body may already have produced side effects before post-execute changes the result to an error. An agent can reasonably interpret that result as “the tool did not execute” and retry, duplicating a write, command, or other side effect.
Why simply swallowing the exception is unsafe
Post-execute hooks may implement permission checks, policy enforcement, or other security-sensitive controls. Silently ignoring an exception would risk fail-open behavior. The existing fail-closed direction is understandable; the issue is that it currently provides little attribution or containment when a global third-party listener is defective.
Possible improvements
Include listener provenance in post-execute failures: plugin identity, scope, and registration source where available.
Provide diagnostics and a controlled circuit-breaker mechanism for repeated failures, while keeping enforcement/policy listeners fail-closed.
Distinguish policy/enforcement listeners from decoration/observation listeners, with deliberately different isolation semantics.
Offer tool-specific result-processing APIs so plugins do not need a broad global hook for a single tool type.
Add plugin development guidance and integration tests that mount a plugin and then execute an unrelated tool.
Consider an explicit result state for “tool body completed, post-processing failed,” so agents do not mistake it for a non-executed operation and retry side effects.
Environment
Windows; DSH 0.1.0-rc.5.
Would maintainers be open to discussing the best combination of provenance, fail-closed containment, and post-execution outcome semantics here?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
A faulty in-process third-party plugin can currently make unrelated tools appear to fail after they have already executed.
In the incident that prompted this discussion,
@deepseek-ai/dsh-tool-indexed-searchregistered a globaltools/post-executelistener intended to processlocateresults. The listener did not first checkexec.name === 'locate', so it attempted to accessvalue.results.lengthfor results from unrelated tools such asread,pwsh,glob,skill,Cordis, andjob_list. Those values do not necessarily have aresultsproperty, producing:Cannot read properties of undefined (reading 'length')This is directly a plugin bug, not a claim that DSH core tools are broken. However, it exposes a fault-isolation, diagnostics, and side-effect ambiguity gap at the trusted in-process post-execute extension point.
Minimal reproduction
A listener shaped like this is sufficient:
If it is registered globally and omits an
exec.name === 'locate'guard, a non-locateresult can cause the listener to throw.Observed behavior
readcall immediately failed attools/post-execute.pwsh,glob,skill,job_list, andCordis) all returned the same error; more than 20 calls were affected.packages/core/tools/src/index.ts,finalizeScheduledExecution/postExecuteconverts a throwing post-execute listener into anisErrorresult.packages/core/tools/tests/tools.spec.tsexplicitly tests this behavior.The most concerning consequence is semantic: the tool body may already have produced side effects before post-execute changes the result to an error. An agent can reasonably interpret that result as “the tool did not execute” and retry, duplicating a write, command, or other side effect.
Why simply swallowing the exception is unsafe
Post-execute hooks may implement permission checks, policy enforcement, or other security-sensitive controls. Silently ignoring an exception would risk fail-open behavior. The existing fail-closed direction is understandable; the issue is that it currently provides little attribution or containment when a global third-party listener is defective.
Possible improvements
Environment
Windows; DSH
0.1.0-rc.5.Would maintainers be open to discussing the best combination of provenance, fail-closed containment, and post-execution outcome semantics here?
All reactions