Skip to content

[Bug]: Codex fork requests full history, exceeding transport limits on large threads #24460

Description

@felho

Before submitting

  • I searched existing issues and pull requests and did not find a report specifically covering the remaining full-history Codex fork request.
  • I included observed behavior, measurements, source references, and verification limits.

Area

apps/server — Codex adapter and app-server transport

Summary

Forking a large Codex conversation requests the complete historical thread.turns payload even though the adapter returns thread metadata. On the installed build this repeatedly left every new Codex and Claude turn stuck on Thinking. Current main has since added a 128 MiB transport limit, but forkThread still omits excludeTurns: true, so the oversized response remains an obstacle to forking these conversations.

This is a follow-up to the already-fixed unbounded-input issue, not a claim that current main still exhibits the same global hang.

Steps to reproduce

Observed on the installed desktop build:

  1. Use an existing Codex conversation with extensive tool/file-change history. In this case, reading the resulting fork's full history produced one approximately 590 MB JSON-RPC response.
  2. Fork from a completed assistant response and send the first message in the new thread.
  3. T3 sends thread/fork with threadId and lastTurnId, without excludeTurns.
  4. Continue three other Codex threads sharing that app-server process.
  5. Send a short message in a new thread, including a Claude thread.

The fork and three resume operations remained running, occupying all four effect workers; subsequent starts and title-generation effects remained pending. Restarting the T3 backend restored service. Retrying the same fork reproduced the stall after restart.

The live reproduction used existing private history, not a shareable clean-session fixture. No private transcript or database is attached.

Expected behavior

Forking should preserve the provider conversation without returning its complete historical turn payload when the adapter only needs metadata. An oversized response must not strand pending requests or block unrelated providers.

Actual behavior and evidence

Sanitized request shape captured on both attempts:

{
  "method": "thread/fork",
  "params": {
    "threadId": "<source-thread>",
    "lastTurnId": "<completed-turn>",
    "cwd": "<workspace>",
    "model": "gpt-6-astra"
  }
}

The shared Codex process remained alive and logged outgoing events after T3 stopped recording incoming protocol messages. Terminating that Codex process did not release the waiting operations; restarting the T3 backend did. After the first restart, separate Codex and Claude ping tests both completed, before retrying the fork reproduced the stall.

An isolated app-server read-only probe of the already-created fork, using thread/read with includeTurns: true, measured:

Response bytes:             590,282,432
Response UTF-16 code units: 589,429,682
Read completed in:          2.68 seconds
T3 runtime MAX_STRING_LENGTH: 536,870,888

These are measurements of a separate thread/read response for the fork, not a captured original thread/fork response. No inference turn was started by the probe.

The installed Electron runtime also reproduced the line-assembly failure with synthetic fragments:

const { MAX_STRING_LENGTH } = require("node:buffer").constants;
const size = 589429682;
const fragment = "x".repeat(65536);
const fragments = Array(Math.floor(size / fragment.length)).fill(fragment);
fragments.push("x".repeat(size % fragment.length));
console.log(MAX_STRING_LENGTH); // 536870888
fragments.join(""); // RangeError: Invalid string length

No original live RangeError stack was captured. The reader-fiber failure explanation is supported by the payload measurement, synthetic failure, source inspection, and repeated live symptoms; it is not an instrumented trace of the original exception.

Source inspection and current-main status

Installed build: 81493efb71e8e8244f95d3e9f71d8369654ab151 (2026-10-15).

Checked main: d53873b6a4799e87afd63c8d288ef0089f5a3748 (2026-10-24).

Current main was inspected, not executed against this history. Successful fork behavior or the exact user-visible error/recovery behavior after #19733 has not been verified here.

Suggested direction

Request excludeTurns: true on the fork path, ensuring it survives generated-schema encoding (the resume path uses a raw request for this reason). Verify the fork still preserves context and boundary semantics while only returning metadata. Add focused coverage for the outgoing fork request and for pending-request completion when the transport reader fails.

Codex documents the metadata-only fork option in ThreadForkParams.

Impact

Blocks work completely on the installed build once the shared workers are occupied. The remaining current-main concern is that large native forks still request responses exceeding the transport limit.

Version and environment

  • T3 Code Beta desktop, package/build version 0.1.0, commit 81493efb71e8.
  • macOS 26.6.2 (25G83), Apple Silicon.
  • Bundled Electron 44.4.5 / Node.js v24.21.0.
  • Codex CLI 0.164.0, shared local app-server, GPT-6-Astra.

Related issues and fixes

Workaround

Restart the T3 backend to release the stuck work, then avoid retrying the affected fork. A fresh conversation avoids copying that provider history. An update containing #19733 should provide the size guard, but has not been tested here and does not by itself remove full-history fork requests. No application source or live database was manually modified.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions