{"record":{"id":"1560c6ce3bef5827","repo":"can1357/oh-my-pi","slug":"claude-command-exited-before-v1-messages-complete","errorCode":null,"errorMessage":"Claude command exited before /v1/messages completed${outputSuffix()}","messagePattern":"Claude command exited before /v1/messages completed(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/claude-trace-cli.ts","lineNumber":781,"sourceCode":"\t\tconst first = await Promise.race([captureRace, ptyRace]);\n\t\tif (first.kind === \"capture\") {\n\t\t\tawait shutdownPty(session, runPromise);\n\t\t\treturn first.exchange;\n\t\t}\n\t\tif (first.kind === \"capture-error\") {\n\t\t\tthrow new Error(`${errorMessage(first.error)}${outputSuffix()}`);\n\t\t}\n\t\tconst late = await Promise.race([captureRace, Bun.sleep(250).then(() => ({ kind: \"late-timeout\" as const }))]);\n\t\tif (late.kind === \"capture\") {\n\t\t\tawait shutdownPty(session, runPromise);\n\t\t\treturn late.exchange;\n\t\t}\n\t\tif (first.kind === \"pty-error\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Claude command failed before /v1/messages completed: ${errorMessage(first.error)}${outputSuffix()}`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(`Claude command exited before /v1/messages completed${outputSuffix()}`);\n\t} finally {\n\t\tterminal.dispose();\n\t\tawait proxy.stop();\n\t}\n}\n\nexport async function runClaudeTraceCommand(args: ClaudeTraceCommandArgs = {}): Promise<void> {\n\tprocess.stderr.write(\n\t\t`Starting Claude trace proxy on ${args.host ?? DEFAULT_PROXY_HOST}:${args.port ?? DEFAULT_PROXY_PORT}\\n`,\n\t);\n\tconst exchange = await runClaudeMessagesCapture(args);\n\tconst output = args.json ? `${JSON.stringify(exchange, null, 2)}\\n` : formatCapturedMessagesExchange(exchange);\n\tprocess.stdout.write(output.endsWith(\"\\n\") ? output : `${output}\\n`);\n}\n","sourceCodeStart":763,"sourceCodeEnd":796,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/claude-trace-cli.ts#L763-L796","documentation":"The fallback case of the capture race: the Claude command exited (without an error object) before any /v1/messages exchange was captured, and even after the 250ms late-capture grace window no exchange arrived. The trace throws with any captured output appended so the developer can see why Claude quit.","triggerScenarios":"The PTY session observes claude exiting normally-but-early (exit event, not an error throw) with no /v1/messages capture completing — e.g. claude exited instantly, rejected the prompt interactively, or the session ended before the API call.","commonSituations":"claude CLI printed a usage/help screen and exited; interactive confirmation or TOS-acceptance prompt stalled then exited; extremely fast failure where pty-error vs exit classification landed on the exit branch; network so fast the capture missed the exchange (rare).","solutions":["Read the outputSuffix() capture output included in the message — it shows what claude printed before exiting.","Run `claude -p 'hi'` manually to see the early exit (help text, TOS prompt, auth wall) and fix it.","Increase --input-delay so the prompt is typed after claude fully initializes.","Re-run the trace; if the capture keeps missing fast exchanges, check proxy/TLS setup so the exchange is recorded on time."],"exampleFix":"// before: claude exits showing onboarding prompt\n$ omp claude-trace\n// after: pre-accept onboarding, then trace\n$ claude  # complete onboarding once\n$ omp claude-trace","handlingStrategy":"validation","validationCode":"const check = await Bun.$`claude --version`.quiet().nothrow();\nif (check.exitCode !== 0) throw new Error(\"claude CLI missing or failing at startup\");","typeGuard":null,"tryCatchPattern":"try {\n  const exchange = await runTrace();\n} catch (err) {\n  if ((err as Error).message.includes(\"exited before /v1/messages completed\")) {\n    // inspect the captured output appended to the message for claude's final output\n  } else throw err;\n}","preventionTips":["Complete claude onboarding/TOS interactively once before tracing","Raise --input-delay so the prompt is typed only after claude fully initializes","Read the captured output in the error message first — it usually names the early-exit reason"],"tags":["claude-code","pty","process-exit"],"backgroundTag":"claude-command-exited-early","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}