fix(tui_rpc): surface the cause of an internal_error, not just the code - #296
Open
arelchan wants to merge 1 commit into
Open
fix(tui_rpc): surface the cause of an internal_error, not just the code#296arelchan wants to merge 1 commit into
arelchan wants to merge 1 commit into
Conversation
A -32603 reached the user as the bare line `error: [rpc -32603]
internal_error`, with nothing about what failed or where to look. The cause
was collected and then thrown away three times over:
- the dispatcher dropped `RpcError.detail` whenever the raiser also passed
`data`, which `_build_tui_agent_loop` always does;
- `turn.send` emitted a latched init crash as `{code, message}` only, even
though the ErrorEvent schema already has a `detail` field the front end
renders;
- the client formatted `[rpc <code>] <message>`, where `message` is a fixed
code name, and every call site prints `err.message`.
So an AgentLoop that cannot start (a config the running branch cannot parse,
for instance) produced an error that named neither the file nor the log.
Fold `detail` into `error.data` in a shared `error_data` helper used by both
the dispatcher and the turn events, pass the init-crash detail plus its
`log_path` into the emitted event, and build the client-side message from
`detail` / `exception_message` / `reason` with the log path appended. A
multi-line cause (a config error listing each offending field) keeps its
line breaks below the summary line.
Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A -32603 reached the user as exactly this, and nothing else:
No cause, no file, no log path. The information existed the whole time and was discarded
three separate times:
detail.raven/tui_rpc/dispatcher.pyusedif exc.data is not None: ... elif exc.detail: ..., so a raiser that set both lost thedetail.
_build_tui_agent_loopalways sets both.turn.sendemitted only{code, message}for a latched init crash, although theErrorEventschema already has adetailfield andchatStream.onErroralready rendersit.
[rpc <code>] <message>, wheremessageis a fixed code name(
internal_error), and every call site printserr.message.So an AgentLoop that cannot start produced a dead end. A real instance: a config file
containing a key the running branch does not know about fails validation,
_build_tui_agent_loopraises
InternalErrorwith the full pydantic message andlog_path, and the TUI showed theline above.
The fix keeps
messageprotocol-faithful and puts the cause where callers already look:error_data(exc)inraven/tui_rpc/errors.pyfoldsdetailintodata, and both thedispatcher and the turn error events use it, so the two paths carry the same context.
turn.sendpasses the init-crash detail plus itslog_pathinto the emitted event.formatRpcErrorinui-tui/src/rpc/errors.tsbuilds the message fromdetail,exception_messageorreason, and appends the log path. A multi-line cause (a configerror listing each offending field) keeps its line breaks below the summary line.
Same failure after the change, rendered by feeding a real dispatcher frame through the client
path:
Type
Verification
uv run pytest tests/ -k "tui_rpc or dispatcher or tui_bootstrap"-> 523 passed. New cases:the dispatcher keeps
detailnext toreasonandlog_pathin one frame;turn.sendemitsthe build-error cause with its log path; and it omits
detailentirely when the error has nocause to report.
npx vitest runinui-tui/-> 86 files, 988 tests passed, including six newrpcErrorFromFramecases: a bare frame keeps the old one-line form;datacontext issurfaced with the log path;
exception_messageandreasonare read whendetailis absent;a multi-line cause keeps its shape; non-object or blank
datacannot corrupt the message; andtyped subclass selection plus raw
dataaccess are unchanged.npm run type-check,npx eslint,npx prettier --check,ruff check,ruff format --checkall clean.
End to end, the exact production shape: an
InternalErrorraised the way_build_tui_agent_loopraises it was dispatched to a JSON-RPC frame, and that frame was fedthrough
rpcErrorFromFramewithtsx, producing the output shown above.Risk
Notes:
error.codeanderror.messageare unchanged on the wire, so nothing that branches onthem is affected; the added
data.detailandpayload.detailare both already in the schema.err.messagegains a suffix, which the one message-matching call site(
SESSION_BUSY_REinuseSubmission.ts) is unaffected by, since it matches text that stillappears. Detail text originates from server-side exceptions and is already written to
~/.raven/logs/tui.log, so this exposes nothing new to the client; the client accepts it onlywhen it is a string and ignores any other shape. Rollback is a revert of this commit.
Related Issues
N/A