A single invalid UTF-8 rollout record makes the entire thread unreadable
What happened?
A legacy rollout JSONL containing one newline-terminated partial record with an incomplete multibyte UTF-8 sequence cannot be opened or resumed. Thread loading fails before the existing per-record JSON recovery logic can run:
failed to load thread history: stream did not contain valid UTF-8
All valid records before and after the damaged record remain present on disk, but the entire thread becomes unreadable.
Deterministic reproduction
A sanitized regression test is available on this branch:
https://github.com/shtse8/codex/compare/openai:main...shtse8:codex:fix/skip-truncated-rollout-record
The fixture writes:
- a valid
session_metarecord; - a newline-terminated partial
agent_messagerecord ending with bytese6 87(an incomplete three-byte UTF-8 sequence); - a complete valid
agent_messagerecord.
On unmodified main (1bbfb5cfada8e56280adcd397b23d0c301423894), this test fails with:
Error: Custom { kind: InvalidData, error: "stream did not contain valid UTF-8" }
Root cause
RolloutRecorder::load_rollout_items consumes RolloutLineReader::next_line(). The plain reader is backed by tokio::io::AsyncBufReadExt::lines(), which decodes UTF-8 before serde_json sees each record. Invalid UTF-8 therefore aborts the stream instead of entering the existing parse-error path that already skips malformed JSON records.
Proposed fix
Read JSONL boundaries as bytes for rollout replay, then call serde_json::from_slice per record. An invalid UTF-8 record is counted in the existing parse_errors total and skipped, while subsequent valid records continue loading. Keep RolloutLineReader::next_line() strict for callers that explicitly request strings. The implementation covers both plain and zstd-compressed readers.
The branch above includes the focused implementation and regression test. No user rollout, conversation content, or credentials are included.
Verification
- regression test: red on unmodified
main, green after the fix; just test -p codex-rollout: 113 passed;just fix -p codex-rollout;just fmt;git diff --check.
Per the invitation-only contribution policy, please treat this as a request for maintainer review of the approach and an invitation to open the prepared PR if it aligns with the intended recovery semantics.
Where are you seeing the problem?
Codex desktop app connected to a Linux remote workspace.
What version of Codex are you using?
Reproduced against upstream main at 1bbfb5cfada8e56280adcd397b23d0c301423894.
What operating system are you using?
macOS desktop client with a Linux remote workspace.
1 Comment
A second independent occurrence reproduced the same failure on 2026-08-06 with
codex-cli 0.146.0in a Linux remote workspace.Sanitized evidence:
e7byte inside an unfinishedagent_messagestring;stream did not contain valid UTF-8;This further isolates the availability failure to UTF-8 decoding in the line-reader layer before the existing malformed-JSON recovery path. No rollout content or user transcript is included here.