[0.153.4] Rollout migration drops compacted records over 16 MiB; suspected cause of context overflow after resume
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using (From “About Codex” dialog)?
26.903.61454 (bundled CLI/app-server 0.153.4)
What subscription do you have?
Not disclosed (privacy).
What platform is your computer?
macOS
What issue are you seeing?
Summary
The legacy-to-paginated rollout reader discards any individual JSONL record larger than 16 MiB before parsing its type. This also affects compacted records containing replacement_history and guardian_history. Ordinary compaction persistence can write such records without that limit.
Requested action: preserve these replay-critical checkpoints during migration, or fail without publishing the replacement rollout. Add regression coverage for oversized compacted records and resume equivalence. This request follows from the reader/writer mismatch even if the incident's complete causal chain cannot yet be reproduced.
A long-running, image-containing task successfully compacted and continued working, but later failed with context-window errors after reopening. Local inspection found multiple compaction completion markers without corresponding full checkpoint records. The last surviving checkpoint was just below the migration limit.
Evidence boundary: the size filter is confirmed in source. Its responsibility for the missing checkpoints and the subsequent overflow is a strong hypothesis, not a captured before/after migration reproduction. No per-record deletion log or pre-migration snapshot was available.
Environment
Background paginated-rollout migration was enabled; the inspected history was already paginated. The first failure happened before custom context-window overrides were added. Increasing the configured window afterward did not recover the task.
Confirmed source behavior
References are pinned to rust-v0.153.4:
read_rollout_recorduses a 16 MiB per-line limit. An oversized line is drained and returned asline: None, regardless of record type.- The canonicalization loop skips those records. Successful migration then publishes the replacement file.
replace_compacted_historystores the replacement history and auxiliary guardian history in oneCompactedrecord. The ordinary rollout writer serializes and writes the whole record without this size filter.
The reader's size check and discard branch are also present in the main-branch source inspected while preparing this report. This is source inspection, not a runtime test of a newer release.
Sanitized observations from the affected history
The local rollout contained several hundred successful-compaction markers, but the latest group of markers had no corresponding full top-level compacted records. Matching the event sequence, not just comparing aggregate counts, identified this gap.
The last surviving full checkpoint was approximately 15.5 MiB, just below the 16 MiB reader limit. Its replacement history retained many user images, and its auxiliary guardian history also contained image data. Image-URL fields dominated the physical record. Auxiliary images may duplicate main-history images and must not all be counted as main-model input.
After an additional image-containing user record, the next successful-compaction marker lacked its full checkpoint body in the inspected canonical history, as did later completions. The original sizes of the missing checkpoint records cannot be measured from the remaining file.
Compaction was demonstrably effective while the task was running: successful model requests immediately afterward had substantially fewer input tokens than the pre-compaction context. After reopening, a short user message failed with:
Codex ran out of room in the model's context window.
Subsequent remote-compaction attempts also failed. A fork inheriting the affected history failed too. The user-visible error recommended starting a new thread or clearing earlier history.
The UI later displayed a completely full enlarged window, but the associated error record had zero input/output tokens and a total set to the window maximum. That display is not proof of a measured prompt of that exact token count. Disk bytes, image-URL lengths, and model tokens are separate measurements.
Suspected failure sequence
- Compaction succeeds in memory and writes an image-containing replacement-history snapshot.
- A later migration encounters an oversized checkpoint record and omits it from the replacement rollout.
- The live task can continue using its in-memory state, so loss is not immediately visible.
- Resume/fork reconstructs history using an older surviving checkpoint plus subsequent raw records.
- The reconstructed input exceeds the model window, and remote compaction cannot recover it.
The surviving older checkpoint was followed by millions of characters of tool-heavy history before the affected fork's inherited boundary. This supports the replay-inflation hypothesis, but the complete failed server-side prompt and its actual token count were not captured.
What steps can reproduce the bug?
These are proposed tests for the production migration path; they have not been executed as an isolated end-to-end reproduction in this report.
- Build a synthetic legacy rollout with valid session metadata, an earlier checkpoint, intervening tool output, a later valid
compactedrecord larger than 16 MiB, and a trailing small user message. Use placeholder image data, not private screenshots. - Run the real legacy-to-paginated migration against that isolated fixture.
- Assert that migration either preserves the latest checkpoint's effective replacement history or fails without replacing the original file. Continuing past the oversized record while losing it must fail the test.
- Compare resume history before and after migration; superseded tool output must not re-enter effective context because a checkpoint was lost.
- Cover records just below, at, and above the limit, including a record exceeding the limit primarily because of
guardian_history.
The immediate safeguard could be to fail migration without publishing on oversized state-bearing records. Longer-term options include streaming preservation or externalizing large media. Simply increasing the limit would postpone the same class of failure.
What is the expected behavior?
Migration should preserve the effective compacted context needed for resume. If a checkpoint cannot be migrated safely, it should leave the original history intact and report an actionable failure, rather than publish history with the checkpoint omitted.
Compaction completion markers alone should not be treated as proof that the corresponding resumable context is present.
Additional information
Related reports
- #24948 documents rollout growth and repeated image-containing compaction snapshots.
- #38835 documents raw-media retention across remote compaction.
This report focuses on the additional persistence failure: a generic per-record migration limit can remove a successfully generated compaction checkpoint and change the history used on resume.
This report was prepared with Codex assistance from local, read-only inspection. Private conversation content, screenshots, credentials, project names, task identifiers, and raw diagnostic files are omitted.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with read_rollout_record and the canonicalization loop in codex-rs/thread-store/src/local/rollout_migration.rs, then inspect replace_compacted_history and the rollout writer paths named in the report. Build an isolated migration fixture with oversized compacted records, including guardian_history, and compare resume history before and after migration. Done means the checkpoint is preserved or migration fails without replacing the original file, with coverage below, at, and above the limit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100