Repository navigation
Description
Description
Interrupting a turn and then sending an explicit stop message does not stop the agent. The next assistant step re-requests permission for the same action, so every stop message produces exactly one new permission prompt. There is no session-level "user asked to stop" state that survives into the following step, and the only way to end the loop is to close the session.
Measured from one session (ses_f0f92404…, all times UTC):
| time | event |
|---|---|
| 10:29:27 | idle → outcome=interrupted |
| 10:29:31 | step → tool call #1 shell, denied after 4.4s |
| 10:29:48 | user: "stop" |
| 10:35:53 | step → tool call #2 shell — pending 8.7 min before denied |
| 10:44:41 | user: "stop" |
| 10:44:54 | step → tool call #3 shell, denied after 1.4 min |
| 10:46:21 | idle → outcome=interrupted; user closes session |
Two things make this worse than a normal rejected call:
- The pending request is not cancellable and is not tied to the turn. During the 8.7-minute window the only action available was Reject, which per [BUG]: Desktop: denying a tool permission prompt silently stops the whole agent turn (replacement for stale-closed #30726) #44255 ends the turn. The user is funnelled into the exact behaviour already reported there.
- The signal the model receives is ambiguous. Each attempt ends with
{"type":"aborted","message":"The user declined this tool call"}plusfinish=error. Nothing distinguishes "reject this one call, continue" from "I want you to stop". The model reasonably reads it as a failed approach and retries, so the loop persists across turns.
All three calls record executed: false, so nothing ran — impact is a prompt loop, not data loss.
Also worth noting: no message=asking … permission= line is written to opencode.log on 2.0.19 (last one is dated 2026-09-03 on 1.18.x), so this had to be reconstructed from the session_message table.
Steps to reproduce
- Configure a tool to
ask(nopermissionblock was set here;shellprompted via external-directory access to paths outside the project). - Run a session and give a task that requires that tool.
- Interrupt the turn, then send a plain-language stop message ("stop", "bro dursana").
- Reject the permission prompt that appears.
- Repeat step 3–4: each new stop message yields another prompt for the same action.
- Only closing the session ends it.
Intermittent in the sense that it needs a multi-step task; deterministic once the loop starts (3/3 prompts here).
OpenCode version
2.0.19 (channel=latest; 2.0.22 available). Long-lived opencode serve --service process, client attached/detached across the session.
Plugins
None. Two local stdio MCP servers configured (blender, unity), unrelated to the failure.
Operating System
WSL2: Linux 6.18.33.2-microsoft-standard-WSL2 (x64), Windows 11 host, project workspace on /mnt/c.
Terminal
Windows Terminal (WT_SESSION set), TERM=xterm-256color, shell /bin/bash.
Related
#44255 / #45273 (reject semantics), #44747 (stop/interrupt no-ops), #37007 / #40829 (abort waiting on tool), #51224 / #52846 (pending-request lifecycle). The distinction here is that no step carries forward an aborted/halted state, so the retry happens in a new turn rather than within one.
Activity
github-actions commentedon Oct 4, 2026
This issue might be a duplicate of an existing issue. Please check:
opencodejr commentedon Oct 27, 2026
Thanks for the detailed timeline. It makes the loop easy to follow.
As far as I can tell, each piece is working as designed in v2: declining a permission ends the current turn and marks the call as aborted ("The user declined this tool call"). Sending "stop" then starts a normal new turn, and the model decides to try the same
shellcall again, which correctly asks for permission again. So what you're describing is a request for new behaviour:I've marked this as a feature request so maintainers can consider it. I can't say whether or when it will be picked up.
Related issues:
In the meantime, a stop message that is more explicit about tools, e.g. "stop, do not call any more tools", may help, or you can allow or deny that specific external-directory path in your
permissionconfig so the prompt doesn't come back.