DeepSeek Harness aborts tool calls before dispatch
Mid-turn you switch to /permission auto, and from the next tool call onward everything returns ABORTED_BEFORE_DISPATCH, while the turn still ends as completed. The error text is only two lines: tool call aborted before dispatch and code: "ABORTED_BEFORE_DISPATCH". This is not the model misbehaving and not a broken tool: DeepSeek Harness (DSH) reconfigures auto-review when the permission preset changes, and that teardown only half-runs (source).
Confirm the cancel follows a preset switch in DeepSeek Harness
All three conditions must hold: tools worked before the switch, every call after it is cancelled, and the turn still reports completed. If one is missing, leave the DSH plugin configuration alone.
- Find the preset-change event in the session log. Expected: every
tool/callafter it pairs with anAbortError. - Look for evidence that a tool body started, such as file content or command output. Expected: none at all.
- Confirm the profile mounts auto-review and the preset is
auto. Expected: the plugin appears in the list and the shield shows auto. - Compare with calls before the switch. Expected: earlier results are complete, failures cluster after the switch.
- Record the gap between the switch and the first failure. Expected: nearly zero.
| Signal | This fault | Tool timeout | User abort |
|---|---|---|---|
| Tool body event | absent | present | may be present |
| Turn state | completed | usually failed | aborted |
| Trigger | after a preset switch | during execution | manual stop |
In the discussion's user scan, one sample accumulated 47 of these errors across five sessions, all after a preset change or a plugin reconfiguration (#10041).
Why the DeepSeek Harness disposal only half-runs
disposal sets accepting to false before it repairs sessions, the repair sweep throws, and the throw skips every cleanup that would remove the gate.
- The first statement in disposal sets
accepting = false. Expected: the gate stops accepting reviews. - Disposal then walks active sessions to move their preset from
autoback todanger-full-access. Expected: this path readssessionProjections. - During teardown the fiber is unloading, so that read throws
inactive context. Expected: the sweep aborts. - Disposers run on a promise chain; after the sweep rejects,
stopContributionandstopListenernever run. Expected: the gate stays installed. - The preset still registers
auto, the gate is still there, andacceptingis false. Expected: every later tool call getscancel.
Registration order is stopListener, stopContribution, then sweep, so reverse execution runs the sweep first. A cleanup that can throw sits ahead of the cleanup that removes the gate. Ending the turn does not help either: the bad state lives on the plugin, and a turn is only an execution unit.
A separate sample shows some cancels after a full review round trip, so more than one path reaches the bad state. A session that still resolves to auto has only one exit.
Path 1: return to a fixed preset in DeepSeek Harness
This is the fastest recovery and should come first: the gate's first check passes as soon as the session no longer resolves to auto.
- Run
/permission workspace-writeor another fixed preset in the input box. Expected: the shield shows the fixed preset. - Before ending the turn, call a read-only tool such as reading a known file. Expected: it returns content and does not abort.
- End the turn normally. Expected: no new cancels are appended.
- If you still want auto, switch only after the next turn starts. Expected: the first low-risk tool runs after a review round trip.
- Note the time of the switch. Expected: a future reproduction can be matched against it.
- Call a write tool as well. Expected: it follows the fixed preset instead of being cancelled.
- Check the shield. Expected: it stays on the fixed preset and does not jump back to auto.
The cost is losing auto review for a while. That is fine when you need to keep working, but it is not a repair.
Path 2: restart DeepSeek Harness or open a new session
A restart rebuilds the disposal chain and a new session avoids the half-removed gate; both work, and neither fixes the cause.
- Quit DSH fully, including tray and background processes. Expected: no DSH process remains.
- Start DSH and create a new session rather than reopening the old one. Expected: permissions start from defaults.
- Run a minimal tool, such as listing a directory. Expected: normal output with no cancel.
- If you need the old context, carry file paths and conclusions into the new session. Expected: work continues without the broken turn.
- Watch for ten minutes. Expected: no cancel returns.
- Call one read-only tool in the old session. Expected: if it still cancels, the bad gate was persisted.
- Compare the two sessions. Expected: the new one is clean, the old one keeps the residue.
If you reload plugins or switch presets often, this path only buys time. The next reconfiguration can break the gate again.
Path 3: fix the disposal order in DeepSeek Harness
Run the throwing sweep last, tolerate failures per session, and return a deny with a reason instead of a silent cancel when the gate is closed.
- Move the sweep's
yieldbeforestopListenerandstopContributionin registration order. Expected: reverse execution removes the gate first. - Wrap each session in
try/catchinside the sweep, logging and continuing when a projection read fails. Expected: one bad session no longer abandons the rest. - Change the gate's
accepting === falseresult fromcancelto a deny with a reason. Expected: the user sees "auto-review unavailable". - Add a regression that injects a projection failure into the sweep. Expected: the gate is still removed and later calls receive the deny reason.
- Add an ordering test that rejects mid-disposal. Expected: the remaining disposers still run.
- Attach the 47-error sample distribution to the pull request. Expected: maintainers can judge the blast radius.
The ordering test matters more than the feature test: this defect only appears when one step throws, and the happy path never exercises it.
Do not stop at wrapping the sweep in try/catch. If the gate is still removed last, a future throwing step reintroduces the same half-torn state.
Reproduce and set bounds for DeepSeek Harness
Reproduce only with auto-review mounted and after a turn has started; without a running turn, the sweep has nothing to repair and the bug will not appear.
- Create a session with
workspace-writeand send a request that triggers two tool calls. Expected: both run. - Switch to
/permission autoafter the first tool finishes and before the second starts. Expected: later calls abort. - Switch back to
workspace-writeand call another tool. Expected: execution resumes. - Save the log lines around the switch. Expected: one disposal throw is visible.
- Check the turn state. Expected: completed, even though no tool body ran.
- Count the cancels. Expected: one per tool call attempted after the switch.
- Run another turn under the fixed preset. Expected: zero cancels as a control.
Collect evidence on only three points: where the cancel starts, whether any tool body events exist, and whether a disposal throw sits near the switch. Four limits apply: do not toggle presets to experiment, disabling auto-review stops the bleeding but is a workaround, a completed turn is not a success so rerun steps that depended on tool side effects, and no official fixed version is named in the discussion. For the related startup deadlock, see permission auto deadlock; for the generic missing-service diagnosis, see sessionProjections inactive context.
FAQ
The auto-review gate in DeepSeek Harness returns cancel; the tools never fail. A plugin reconfiguration tears the gate down halfway, so it stays installed but stops accepting reviews and cancels every session still resolving to auto.
The DeepSeek Harness gate first checks whether the preset equals auto. The broken gate only releases when the session stops resolving to auto, and ending a turn does not change the preset, so the cancel carries over.
A restart only lets this teardown finish; it does not repair the DeepSeek Harness ordering defect. Any later plugin reconfiguration with an auto session running reproduces the half-torn state.
Compare tool/call with tool/result in DeepSeek Harness. This case shows only AbortError with code ABORTED_BEFORE_DISPATCH, no tool body event and no timeout field, plus a disposal throw near the preset switch.
Related Terms
- ABORTED_BEFORE_DISPATCH
- ABORTED_BEFORE_DISPATCH is the error code DeepSeek Harness returns when a tool call is rejected before dispatch, paired with AbortError. It means the tool body never started, unlike an interruption during execution.— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
- auto-review
- auto-review is DeepSeek Harness's experimental automatic review integration, evaluating each tool call on the tools/pre-execute hook and returning allow, deny, ask, or cancel. It only acts while the permission preset is auto.— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
- disposer chain
- The disposer chain is the set of cleanup functions a Cordis fiber runs in reverse registration order on unload, implemented as a promise chain. Once one step rejects, the later disposers never run.— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
Sources
- #10041 — Switching to /permission auto mid-turn aborts every tool call in that turn before dispatch· deepseek-ai (GitHub Discussions)
- DeepSeek Harness official repository· deepseek-ai (GitHub)