Skip to content

fix(cli): "Something went wrong" hang — consume each SSE stream once - #22

Merged
soydachi merged 1 commit into
mainfrom
fix/consumed-stream-something-went-wrong
Aug 28, 2026
Merged

fix(cli): "Something went wrong" hang — consume each SSE stream once#22
soydachi merged 1 commit into
mainfrom
fix/consumed-stream-something-went-wrong

Conversation

@soydachi

Copy link
Copy Markdown
Member

Problem

ai '<prompt>' printed ◇ Your script: and then died with ▲ Something went wrong, leaving the process hanging with no message (reproduced locally, 2026-08-28).

Cause

getScriptAndInfo returned two readers (readScript, readInfo) over one OpenAI SDK stream. SDK streams are single-consumption: the second iteration throws Cannot iterate over a consumed stream inside readData's detached async IIFE, which had no catch. The read promise never settled, the rejection went unhandled, and @clack/prompts' spinner — which registers a global unhandledRejection handler — printed Something went wrong. Any mid-stream provider error was swallowed the same way.

The readInfo reader was dead code anyway: the explanation has always come from its own second request (explainInSecondRequest).

Fix

  • getScriptAndInfo returns one reader; prompt.ts calls getExplanation directly for the explanation.
  • readData now reject()s through a shared normalizeCompletionError() (extracted from generateCompletion, so request-time and mid-stream failures produce identical actionable KnownErrors); cleans up its keypress listener (previously leaked one per stream) and closes readline in finally.
  • All readData call sites (getExplanation, getRevision, chat.ts) thread apiEndpoint.

Check

New scripts/stream-consume.check.mjs (offline, fake local SSE server, wired into just test):

  • Pre-fix: FAIL: unhandled rejection(s): Cannot iterate over a consumed stream... + FAIL: readScript-on-error-stream never settled
  • Post-fix: PASS

Real PTY smoke of the built binary against the configured provider: script → explanation → Run this script? → Yes → command executed, no Something went wrong.

Gate

just build, just lint, just test, just security (gitleaks, actionlint, npm ci --ignore-scripts, npm audit) all green. Changeset included (patch).

Co-Authored-By: Claude noreply@anthropic.com

getScriptAndInfo handed two readers over one single-consumption OpenAI
SDK stream. Iterating it the second time threw inside readData's
detached async IIFE, so the read promise never settled and the
rejection reached @Clack's global unhandledRejection handler: the UI
froze after 'Your script:' with 'Something went wrong' and nothing
else. The same swallow hid mid-stream provider errors.

- return one reader from getScriptAndInfo; the explanation always
  comes from its own request (explainInSecondRequest)
- readData rejects through shared normalizeCompletionError, removes
  its keypress listener and closes readline in finally
- add offline stream-consume check to just test; changeset included
@soydachi
soydachi merged commit f55e673 into main Aug 28, 2026
4 checks passed
@soydachi soydachi mentioned this pull request Aug 28, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant