Skip to content

TUI crashes with setRawMode failed errno: 9 when permission prompt fires mid-stream #26200

Closed as not planned

Description

@kobicovaldev

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 setRawMode calls with a check that stdin is still a TTY and is not already mid-read; back off and retry on EINTR.
  • c. Treat EBADF/EIO from 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

  1. Configure an agent with a tool set to ask, e.g. in ~/.config/opencode/agents/<agent>.md frontmatter:
    permission:
      webfetch: ask
  2. Send a prompt that produces a long streaming response and triggers a webfetch tool call mid-stream (e.g., asking the agent to research something that requires fetching a URL).
  3. 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

  1. github-actions commented on May 7, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of or related to an existing issue. Please check:

    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.

  2. github-actions commented on Jul 7, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions