anomalyco / anomalyco/opencode

question tool: aborting mid-question leaves the request pending forever and never publishes question.rejected

Open
#46,163 1 comment 0 reactions 1 assignee View on GitHub

@nexxeln is already working on this.

Since Aug 29, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

Aborting a turn while the question tool is waiting for user input kills the turn correctly (message finalized as MessageAbortedError, tool part marked interrupted: true, session idle) — but the pending question is never rejected:

  • it stays in the registry: GET /question still reports it for a dead turn
  • no question.rejected / question.replied event is ever published
  • POST /question/:id/reject on it returns 200 even though the turn is gone

The Desktop app renders the question dock instead of the composer whenever a question exists in its store, and only clears that store on question.replied/question.rejected. Since neither is ever published on abort, the composer stays blocked and Stop is a no-op — the session can't be continued, only an app restart fixes it.

Root cause: Question.ask (packages/opencode/src/question/index.ts) waits with Effect.ensuring(Deferred.await(deferred), pending.delete) — on interrupt the entry is silently dropped/leaked and no event is published. Same shape in Permission.ask. SessionProcessor.cleanup() only marks the tool part errored. All unchanged on latest dev.

Related: #35840 (same family — note that on 1.18.25 the entry leaks rather than being cleaned up, so answering no longer 404s, but the stale-UI outcome is the same), #30066, #15172, #46135, #43376.

Fix suggestion: on turn abort, reject pending asks through the normal path (fail the deferred + publish question.rejected / permission.replied) instead of the silent finalizer. Client-side defense in depth: clear a pending question when its tool part becomes error/interrupted.

Plugins

none

OpenCode version

1.18.25 (also checked: packages/opencode/src/question/index.ts has no changes on latest dev)

Steps to reproduce

Full runnable harness (mock provider + driver + config): https://gist.github.com/henrychu04/ad874b73679b0318a81d4a3ae9db2cf9

The mock is an OpenAI-compatible server whose first completion is a single question tool call, so no real LLM is needed. It ships a mock/mock-model via opencode.json (npm: @ai-sdk/openai-compatible, baseURL: http://127.0.0.1:41123/v1).

# terminal 1
node mock-provider.js                # mock provider on 127.0.0.1:41123

# terminal 2 (isolated data/config so this doesn't touch your install)
git init project
XDG_DATA_HOME="$PWD/data" XDG_CONFIG_HOME="$PWD/config" \
  opencode serve --port 41234 --hostname 127.0.0.1

# terminal 3
REPRO_PROJECT_DIR="$PWD/project" node drive.js

drive.js connects an SSE listener to GET /event, creates a session, sends a prompt (the mock model calls question), waits for question.asked, then POST /session/:id/abort, and prints the resulting timeline:

[+3.280s] SSE  question.asked ...
[+4.284s] >>> POST /session/:id/abort
[+4.571s] SSE  session.status {"status":{"type":"idle"}}
[+4.910s] PROMPT REQUEST RESOLVED: HTTP 200
[+4.911s] SSE  message.part.updated part=tool tool=question status=error err="Tool execution aborted"
[+4.911s] SSE  message.updated  msg error="MessageAbortedError"
[+6.953s] GET /session/status -> {}          (server idle and healthy)
[+6.973s] GET /question -> [ ...aborted question, still pending... ]
[+7.376s] follow-up prompt admitted (HTTP 200)
wire tally: question.asked=1, question.rejected=0, question.replied=0

Finally, POST /question/<que_id>/reject on the ghost returns 200 true.

Operating System

macOS

Terminal

n/a — opencode serve + Desktop app

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.