Skip to content

fix: accept RPC responses up to 64 MiB and refuse a larger success with PROTOCOL_ERROR - #320

Merged
ThomasK33 merged 11 commits into
mainfrom
fix/rpc-response-cap
Nov 4, 2026
Merged

ThomasK33 merged 11 commits into
mainfrom
fix/rpc-response-cap

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Why

sendRpc read at most 1,048,576 characters of a host response. A structured snapshot with cells takes about 56 characters per fully styled cell and about 14 per plain cell. So agent-tty snapshot --include-cells failed on a live session at realistic sizes, with exit 9 RPC_ERROR "RPC response exceeds maximum buffer size.". I measured one response line on live sessions:

Terminal structured + cells Before this PR
200x60 styled 675,160 ok
250x80 styled 1,124,140 exit 9 RPC_ERROR
500x200 plain 1,410,262 exit 9 RPC_ERROR
500x200 styled 5,610,221 exit 9 RPC_ERROR

The other results stay small: a text or structured snapshot without cells of 500x200 takes about 105,000 characters, inspect about 755 and screenshot about 600. The renderer keeps about 75,000 cells of scrollback, so --include-scrollback stays near 95,000.

What changed

  • src/protocol/messages.ts: MAX_RPC_RESPONSE_CHARS = 67,108,864 (64 MiB). That fits about 1.2 million fully styled cells (a 1,000x1,000 screen), 12 times the 500x200 case, and still bounds the memory of one response.
  • src/host/rpcClient.ts: sendRpc reads a response of up to MAX_RPC_RESPONSE_CHARS. It searches only each new chunk for the newline, so reading a large response stays linear (Codex round 1).
  • src/host/rpcServer.ts:
    • The request cap stays at 1,048,576 characters (renamed MAX_RPC_REQUEST_CHARS).
    • sendResponse refuses a success response above MAX_RPC_RESPONSE_CHARS. It sends PROTOCOL_ERROR "RPC response takes N characters, over the 67108864-character limit." with details: { responseChars, maxResponseChars }.
    • The error caps from fix: keep the host running when an RPC error response cannot be built #315 stay at 65,536 characters. The size invariant keeps every error response under 1,048,576, so an older CLI still reads all of them.
  • src/cli/commands/snapshot.ts: a live snapshot with cells waits 60,000 ms instead of the 5,000 ms default (Codex round 1). The host sends nothing until it has built every cell. A fully styled 500x200 snapshot took 1.5 to 1.8 s to its first byte at load average 100 (about 17 microseconds per cell), so a grid near the cap takes about 20 s.
  • Docs: src/host/README.md and src/protocol/README.md.

I chose PROTOCOL_ERROR because it keeps exit 9, the exit code of this failure today. makeCliError marks it not retryable, which is correct here: a retry gives the same size. RPC_ERROR would be marked retryable.

Behavior changes for CLI and JSON users

  • snapshot --include-cells works on a live session up to about 1.2 million styled cells. The envelope shape does not change.
  • Above that, the CLI exits 9 with PROTOCOL_ERROR, a message that names the size and the limit, and both numbers in details. Before, it exited 9 with RPC_ERROR "RPC response exceeds maximum buffer size." and retryable: true.
  • An older CLI on a session that this version started still stops at 1,048,576 characters, as before.

Verification

  • Red first (0a7ca28), on 78ac00b (fix: cap the RPC request id and keep surrogate pairs whole in a shortened message #319's head):
    • test/e2e/large-snapshot.test.ts with the new styled-fill fixture: snapshot --include-cells --json on a live 300x100 fully styled session returns RPC_ERROR "RPC response exceeds maximum buffer size.".
    • test/unit/host/rpcServer.test.ts, with a real RpcServer and sendRpc: a 2,000,000-character text snapshot and a 67,108,864-character one both fail with the same message.
  • Green (d93a8d5, docs 9db4a64 and f81d785):
    • The e2e test passes. Its CLI output is over 1,048,576 characters, with 100 rows of 300 styled cells.
    • The 2,000,000-character snapshot arrives whole. The 64 MiB one gives PROTOCOL_ERROR with maxResponseChars: 67108864.
    • Live, a 500x200 fully styled session gives agent-tty snapshot --include-cells --json with ok: true. The response line takes 5,610,221 characters.
  • Codex round 1 fixes: red b9b502f, fix 51cbc09, docs 041476d.
    • test/unit/commands/snapshot.test.ts: the snapshot RPC with cells gets a 60,000 ms timeout. Before the fix, it was called without one.
    • test/unit/host/rpcServer.test.ts counts the characters that indexOf('\n') reads for a 4,000,000-character response. Before the fix: 149,214,484. After: under 8,000,000.
  • vitest run test/unit: 1987 passed on 041476d. Before the Codex fixes: 1958. vitest run --maxWorkers=1 --retry=2 on host-renderer-rpc and screenshot-out: 17 passed. tsc --noEmit, oxlint src test vitest.config.ts and oxfmt --check pass.

This PR was stacked on #319 (request id cap). #319 has landed, GitHub moved the base to main, and merge commit 17e4ffe brings in main. The diff against main holds only this PR's changes. Refs #315


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T03:54:19.641614Z 17e4ffe Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f81d785ee1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/host/rpcClient.ts Resolved
Comment thread src/host/rpcClient.ts Resolved
Base automatically changed from fix/rpc-request-id-cap to main November 4, 2026 03:49
# Conflicts:
#	src/host/README.md
#	src/host/rpcServer.ts
#	src/protocol/README.md
#	src/protocol/messages.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 17e4ffe6bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 199d613 Nov 4, 2026
18 checks passed
@ThomasK33
ThomasK33 deleted the fix/rpc-response-cap branch November 4, 2026 04:31
@github-actions github-actions Bot mentioned this pull request Nov 4, 2026
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