Codex session replay can fail with invalid_encrypted_content from persisted encrypted reasoning/compaction records

Open 💬 3 comments Opened May 30, 2026 by MagicLuke

Summary

A Codex CLI session under a local repo became impossible to continue because the API rejected persisted encrypted reasoning content during conversation replay:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_encrypted_content",
    "message": "The encrypted content gAAA... could not be verified. Reason: Encrypted content could not be decrypted or parsed."
  },
  "status": 400
}

The user-visible conversation messages were still present locally, but replay failed before the agent could continue.

Environment

  • Codex CLI: codex-cli 0.135.0
  • Install method: npm package @openai/codex
  • Package repository metadata: git+https://github.com/openai/codex.git, directory codex-cli
  • OS: Red Hat Enterprise Linux 9.4 x86_64
  • Auth mode: ChatGPT tokens
  • Session file pattern: $CODEX_HOME/sessions/YYYY/MM/DD/rollout-*.jsonl

What I found in the affected session file

The affected repo-local rollout file had a valid session_meta and most user/assistant events were intact, but it also contained corrupt replay material:

  • 554 top-level response_item rows with payload type: "reasoning" and an encrypted_content field.
  • 4 nested encrypted compaction records inside compacted.payload.replacement_history.
  • 28 malformed JSONL rows, including NUL-byte rows and partial/truncated JSON around the later part of the file.

After removing only those invalid/encrypted replay-only records, the session JSONL parsed again and the user-visible final turns remained available.

Expected behavior

Codex should not fail the whole continuation request when persisted local history contains encrypted reasoning or encrypted compaction blobs that the current client/server can no longer decrypt or parse.

A safer behavior would be one of:

  • skip/drop invalid encrypted reasoning or compaction records during replay,
  • fall back to visible message, event_msg, and tool-output records,
  • detect and repair/ignore malformed JSONL rows before constructing API input,
  • show a local recovery prompt instead of sending invalid encrypted content to the API.

Actual behavior

The continuation failed with invalid_encrypted_content from the API. The user had to manually sanitize the rollout JSONL file before the conversation could be recovered.

Notes

I am not attaching raw rollout history because it can contain private prompts, tool outputs, and encrypted model state. The practical workaround was:

  1. Back up the rollout file byte-for-byte.
  2. Keep parseable JSONL records.
  3. Drop top-level encrypted reasoning records.
  4. Drop nested encrypted compaction/reasoning entries.
  5. Drop malformed/NUL/partial JSON rows.
  6. Verify no structured encrypted_content keys remain and that final user-visible messages are still present.

This seems like a good candidate for a built-in codex doctor or codex repair-history check as well.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗