Skip to content

Codex Desktop SSH handoff fails for conversations larger than 16 MiB because rollout is sent as one WebSocket message #32512

Open

Description

@fkruger

What version of the Codex App are you using (From “About Codex” dialog)?

26.707.41301

What subscription do you have?

Pro

What platform is your computer?

Linux 6.8.0-134-generic x86_64 x86_64

What issue are you seeing?

Summary

A cross-host handoff from Codex Desktop on macOS to a connected Ubuntu SSH
host consistently fails during transfer-host-artifacts when the task has a
large conversation history.

The rollout file is approximately 24.7 MB. Codex attempts to transfer it as one
WebSocket message whose serialized size is 32,936,861 bytes. The remote
app-server rejects it because its per-message limit is 16,777,216 bytes.

This prevents preserving and handing off long-running conversations.

Environment

  • Codex Desktop client build: 26.707.41301
  • Local codex-cli: 0.144.0-alpha.4
  • Local OS: macOS
  • Remote codex-cli: 0.144.1
  • Remote platform: Ubuntu x86_64
  • Connection type: Codex Desktop SSH host
  • Source project: local Git checkout
  • Destination: matching saved project on the SSH host

Steps to reproduce

  1. Create or use a Codex task with a sufficiently large conversation history.
  2. Ensure its rollout JSONL is larger than 16 MiB.
  3. Configure a matching Git project on a connected SSH host.
  4. In a separate coordinator task, hand off the large task to that SSH host.
  5. Wait for the cross-host handoff.

Expected result

The conversation and associated Git state are transferred to the SSH host, and
the task switches to the remote project.

Actual result

prepare-host-transfer completes, but transfer-host-artifacts fails:

Failed to continue on another host:
App-server connection closed before process exited

The remote app-server log contains:

websocket receive error:
Space limit exceeded: Message too long: 32936861 > 16777216

The SSH proxy subsequently reports:

Error: failed to relay data between stdio and socket

Caused by:
    failed to copy data from stdin to socket
    Broken pipe (os error 32)

Relevant sizes

  • Source rollout JSONL: 24,702,507 bytes
  • Source rollout lines: 18,217
  • Serialized WebSocket message: 32,936,861 bytes
  • Remote WebSocket limit: 16,777,216 bytes

Reproducibility

Consistent across repeated attempts.

The following did not help:

  • Rebooting the SSH host
  • Disabling and re-enabling the SSH connector
  • Restarting the remote app-server
  • Staging the task in a local Codex worktree before remote handoff
  • Confirming both repositories are clean and at the same commit

Probable cause

The handoff creates a destination rollout.jsonl using a subprocess similar to:

cat > <handoff-directory>/rollout.jsonl

It appears to send the complete rollout to the remote subprocess in one
WebSocket/process-input message. Conversations whose serialized transfer
payload exceeds the app-server's 16 MiB per-message limit therefore cannot be
handed off.

Requested fix

Please stream or chunk handoff artifacts into messages substantially below the
WebSocket limit, rather than sending the complete rollout in one message.

For example:

  • Send process input in 4–8 MiB chunks, or
  • Transfer the file using a streaming filesystem operation or SSH file transfer.

It would also help if the UI surfaced the underlying size-limit error instead of
only reporting that the app-server connection closed.

Impact

There is currently no supported workaround that both:

  1. Completes the SSH handoff, and
  2. Preserves the complete conversation history.

Summarizing or truncating the task would lose the conversation state that the
handoff feature is intended to preserve.

What steps can reproduce the bug?

Steps to reproduce

  1. Create or use a Codex task with a sufficiently large conversation history.
  2. Ensure its rollout JSONL is larger than 16 MiB.
  3. Configure a matching Git project on a connected SSH host.
  4. In a separate coordinator task, hand off the large task to that SSH host.
  5. Wait for the cross-host handoff.

What is the expected behavior?

Please stream or chunk handoff artifacts into messages substantially below the
WebSocket limit, rather than sending the complete rollout in one message.

Additional information

No response

Activity

  1. added
    appIssues related to the Codex desktop app
    on Jul 12, 2026
  2. added
    bugSomething isn't working
    app-serverIssues involving app server protocol or interfaces
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Jul 12, 2026
  3. sam-ulrich1 commented on Jul 24, 2026

    @sam-ulrich1

    Please fix

  4. bbingz commented on Jul 26, 2026

    @bbingz

    Analysis (community)

    Residual analysis for #32512 (Desktop SSH handoff fails for conversations larger than ~16 MiB because the rollout is sent as one WebSocket message) under docs/contributing.md — invitation-only. No unsolicited PR.

    Root-cause hypothesis

    This is a process/writeStdin artifact transfer failure, not primarily a large thread/resume response. Desktop sent the whole rollout as one base64 delta (~24.7 MB → ~32.9 MB wire); the remote app-server Unix WebSocket acceptor still uses default ~16 MiB Tungstenite limits and fatal-closes on receive overflow — even though the protocol already supports chunked process/writeStdin deltas.

    Verified at HEAD 4c43465133:

    1. Protocol already has the right shape.
    codex-rs/app-server-protocol/src/protocol/v2/process.rs — process/writeStdin carries optional delta_base64 + close_stdin.
    process_exec_processor.rs decodes one supplied delta and writes it to the process. Multiple smaller deltas are valid; a single huge delta is what blows the frame.

    2. Issue body pins the exact path.
    #32512 reports a ~24,702,507-byte rollout becoming one ~32,936,861-byte WebSocket message, rejected at 16,777,216 bytes on the remote app-server during transfer-host-artifacts — classic ~4/3 base64 expansion of a single delta.

    3. Unix acceptor keeps default limits.
    codex-rs/app-server-transport/src/transport/unix_socket.rs upgrades with accept_async under default Tungstenite frame/message limits. A receive-limit error breaks the inbound loop (transport/websocket.rs); the connection then emits ConnectionClosed. By contrast, an in-tree remote client config raises frame/message limits to 128 MiB (app-server-client remote config) — that raise is not applied to the Unix-socket server acceptor.

    4. Scope honesty (MIXED).

    Ranked fix outline:

    1. Desktop (primary): stream process/writeStdin as multiple delta_base64 chunks under the wire cap; final chunk + close_stdin.
    2. OSS defense-in-depth: set explicit max frame/message on the Unix WebSocket acceptor (document the value); surface a typed “payload too large / use chunked writeStdin” error instead of silent fatal close when possible.
    3. Align acceptor limits with the 128 MiB remote-client policy or document why server stays lower and force chunking.
    4. Regression: synthetic multi-delta writeStdin of >16 MiB total succeeds; single >16 MiB delta fails with actionable error.

    Fail-first tests on the OSS side can mock multi-delta vs single-delta without needing full Desktop. Happy to help with acceptor config + error string. No unsolicited PR.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingremotesessionIssues involving session (thread) management, resuming, forking, naming, archiving

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions