Repository navigation
Description
Description
The opencode TUI crashes (exits to shell) when a permission prompt (e.g., webfetch: ask) is raised while the model is actively streaming response text. The crash is reproducible: setting the relevant tool's permission to allow (so no prompt fires) eliminates the crash entirely.
The failure looks like the TUI losing control of its tty when it tries to switch the terminal into raw mode for the permission dialog while the stream is still rendering — they race on stdin/stdout and one of them ends up with a closed/invalid fd.
Log excerpt (the crash sequence, abridged):
... many service=bus type=message.part.delta publishing (streaming model output) ...
INFO service=permission permission=webfetch pattern=https://opencode.ai/docs/agents/ action={"permission":"webfetch","action":"ask","pattern":"*"} evaluated
INFO service=permission id=per_... permission=webfetch patterns=["https://opencode.ai/docs/agents/"] asking
INFO service=bus type=permission.asked publishing
... more message.part.updated events ...
ERROR service=default e=EINTR: interrupted system call, read exception
ERROR service=default error=EINTR: interrupted system call, read process error
INFO service=default worker shutting down
ERROR service=default e=setRawMode failed with errno: 9 exception
ERROR service=default error=setRawMode failed with errno: 9 process error
INFO service=default disposing all instances
ERROR service=default e=EIO: i/o error, write exception
ERROR service=session.processor session.id=ses_... messageID=msg_... error=Aborted process
errno 9 is EBADF (bad file descriptor on stdin), combined with EINTR on read and EIO on write — strongly suggests the TUI's controlling tty was lost or closed underneath it when the permission prompt tried to take over.
Expected behavior: the permission prompt should pause the stream cleanly and present the dialog, or queue itself until the stream completes — not abort the TUI process.
Suspected root cause (for whoever picks this up):
The TUI calls setRawMode on stdin to render the permission prompt while the streaming renderer is still actively writing. The race produces EBADF on setRawMode and EINTR on the in-flight read. Likely fixes to investigate:
- a. Serialize raw-mode changes against the active stream renderer (only one component "owns" the tty at a time).
- b. Guard
setRawModecalls with a check that stdin is still a TTY and is not already mid-read; back off and retry onEINTR. - c. Treat
EBADF/EIOfrom terminal mode changes as recoverable — re-acquire the tty rather than tearing the worker down (worker shutting down→ full process exit is too aggressive).
Plugins
N/A — reproduces independent of plugins; this behavior pre-dates the current plugin set.
OpenCode version
1.14.40 (channel: latest, server backend: hono)
Steps to reproduce
- Configure an agent with a tool set to
ask, e.g. in~/.config/opencode/agents/<agent>.mdfrontmatter:permission: webfetch: ask
- Send a prompt that produces a long streaming response and triggers a
webfetchtool call mid-stream (e.g., asking the agent to research something that requires fetching a URL). - The TUI exits during streaming, dropping the user back to the shell. A new opencode log file is opened on relaunch.
Setting webfetch: allow avoids the prompt and the crash does not occur.
Operating System
macOS 26.4.1 (Darwin 25.4.0)
Terminal
Reproduced in both Apple Terminal.app and the VS Code integrated terminal (TERM=xterm-256color in both).
Activity
github-actions commentedon May 7, 2026
This issue might be a duplicate of or related to an existing issue. Please check:
setRawMode failed with errno: 9(EBADF) error on macOS — though that issue occurs at TUI startup rather than mid-stream when a permission prompt fires. The root cause may be the same or related.If your issue is specifically triggered by the permission prompt racing with active streaming (as you describe), it may be a distinct code path worth tracking separately. Please check #24240 and comment there if it matches your situation, or keep this issue open if the reproduction is distinct.
github-actions commentedon Jul 7, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.