Codex App Bug — attestation generation times out at 100 ms, blocking pre-turn compaction
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- rust
- Domain
- api, backend, networking
Research direction
Start in codex-rs/app-server/src/attestation.rs, inspect ATTESTATION_GENERATE_TIMEOUT and the timeout log, then trace how websocket_connection invokes attestation during run_pre_sampling_compact. Use the WebSocket versus HTTP-SSE behavior and #20619 for context; done means a delayed attestation no longer permanently strands pre-turn compaction and the sub-second timeout is accurately represented in logs.
Written by the indexing model from the issue text.
Description
What version of the Codex App are you using (From "About Codex" dialog)?
26.721.41059
What subscription do you have?
Pro 20x
What platform is your computer?
Darwin 27.0.0 arm64 arm
What issue are you seeing?
ATTESTATION_GENERATE_TIMEOUT in codex-rs/app-server/src/attestation.rs is 100 ms. That is a
tight budget for an IPC round-trip to the desktop app, and when the app does not answer within it
the attestation request is cancelled, the header falls back to
AppServerAttestationStatus::Timeout, and any turn that depends on it fails.
On a long-running thread, one such timeout during pre-turn compaction was enough to strand the
thread: every subsequent turn re-attempted the same compaction and hit the same timeout, so the
thread could not take another turn at all. It surfaced in the UI as IO error broken pipe.
The client log for each failure (thread/turn ids and model retained, no message content):
turn{... model=gpt-5.6-sol codex.turn.reasoning_effort=medium}
:session_task.run:run_turn:run_pre_sampling_compact
:run_auto_compact{reason=ContextLimit phase=PreTurn}
:model_client.stream_responses_websocket{model=gpt-5.6-sol wire_api=responses
transport="responses_websocket" api.path="responses" turn.has_metadata_header=true}
:model_client.websocket_connection{provider=openai wire_api=responses}
: attestation generation request timed out timeout_seconds=0
ERROR codex_core::session::turn ... run_turn: Failed to run pre-sampling compact
Two observations that may help.
The desktop app does answer — just after the deadline. Every timeout is immediately followed by
WARN codex_app_server::outgoing_message could not find callback for Integer(N)
with N incrementing 1..6 across the six retries. The response arrives after
outgoing.cancel_request(&request_id) has already removed the pending callback, so this is a
deadline that is too short rather than a host that fails to respond.
It is specific to the WebSocket path. Attestation is only requested inside
websocket_connection: all 8 occurrences observed here were in that span, and none on any other
transport, across roughly 14.5k WebSocket turns per day. The same thread runs its turns without
incident over HTTP-SSE, which is consistent with #20619 attaching the header at websocket handshake
time. This is also why the failure presents on compaction — that is the path that opens a fresh
connection mid-session.
The log line under-reports the timeout. attestation.rs logs
warn!(
timeout_seconds = timeout_duration.as_secs(),
"attestation generation request timed out"
);
Duration::from_millis(100).as_secs() is 0, so every occurrence reads timeout_seconds=0. That
reads as a misconfigured zero rather than a 100 ms budget, and it cost several hours of misdiagnosis
here before the constant was found. as_millis() would have made the cause obvious from the first
log line.
What steps can reproduce the bug?
Thread id: 019f96f4-d4e8-7751-87c9-beba24bb3330
Model: gpt-5.6-sol, reasoning effort medium
Rollout: 18,883 items / ~152 MB
- Take a thread that occasionally needs
run_pre_sampling_compact. Here that was roughly 8% of
turns — 28 pre-turn compactions across 338 turns on 2026-07-25 — not every turn. - Send a turn while the desktop app is busy enough not to answer
attestation/generatewithin
100 ms. - The attestation request times out and the turn ends with
Failed to run pre-sampling compact.
The failure is self-sustaining rather than transient. A compaction that fails leaves the thread
still over its limit, so the next turn needs one too and fails the same way. One unlucky 100 ms
window therefore takes the thread out permanently, not just for that turn. That is what makes this
worse than a normal flaky-IPC bug: there is no path back, because the operation that would recover
the thread is the operation that cannot run.
Frequency here: 8 occurrences between 2026-07-16 and 2026-07-26. Sporadic single events for the
first ten days, then one thread stuck for roughly 90 minutes, during which every attempted turn
failed. Nothing changed in the app version (unchanged since 2026-07-25 04:57), so the difference
appears to be how quickly the app answers, not a code change.
The same thread had completed 63 successful phase=PreTurn compactions over the previous three
days, so the operation is not inherently broken — it is timing-sensitive, and one loss is enough to
strand the thread.
What is the expected behavior?
A transient IPC delay should not make a thread permanently untakeable.
Concretely, any of:
- Raise
ATTESTATION_GENERATE_TIMEOUT, or make it configurable, so a busy desktop host is tolerated. - Retry with backoff rather than six attempts against the same 100 ms deadline. The current retries
all fail the same way, so they add latency without adding a chance of success. - Treat an attestation timeout as non-fatal for compaction specifically. Failing the whole turn on a
missing anti-abuse header is a strong response to a 100 ms IPC delay, and it leaves the thread
with no path forward, since compaction is required for the next turn to proceed.
Separately and independently: log as_millis() rather than as_secs(), so a sub-second timeout is
not reported as 0.
Additional information
The attestation mechanism was introduced in #20619, which scopes it to "Responses / compaction /
realtime setup paths" — compaction is the path that fails here.
Workaround, for anyone who hits this: setting supports_websockets = false on the model provider
moves the session to HTTP-SSE, which does not request attestation, and the stranded compaction then
completes. Re-enabling WebSocket afterwards is fine — the thread is back under its limit by then.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- Avg merge
- 1m
- Merged PRs (30d)
- 1k
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.
More from openai/codex
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
bug CLI windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
macOS sandbox blocks hw.optional.arm64 sysctl, causing Flutter to misdetect Apple Silicon as x64 Openbug CLI sandbox
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug CLI TUI
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
CLI config enhancement skills
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
A-linter
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
oxc-project/oxc#26863 ·