Skip to content

HTTP-bridge reattach stalls with no response.created and needs a client restart to recover #1534

Description

@lkraider

Version: ghcr.io/soju06/codex-lb:1.22.0
Client: pi coding agent 0.82.1, transport @earendil-works/pi-ai 0.82.1, model gpt-5.6-sol, provider codex-lb, WebSocket endpoint /backend-api/codex/responses.

Summary

When a session is resumed on the HTTP-bridge path, codex-lb reattaches by injecting a stored anchor and full-resending the conversation. If upstream never emits response.created, codex-lb waits its client-safe deadline (_HTTP_BRIDGE_EVENTLESS_RESPONSE_CREATED_MAX_SECONDS = 240), then ends the turn with "Upstream did not acknowledge response.create before the client-safe deadline". Retrying within the same client session rebuilds the identical reattach to the same account and stalls the same way, so the client cannot recover by retrying. Only starting a fresh client session recovers.

Evidence (one session, two consecutive attempts)

event=fresh_reattach_anchor_injected  bridge_key=sha256:7dfa… account_id=…7cb39f74
event=durable_full_resend_anchor_injected  response_id=resp_0563… stored_items=425
event=create  request_stage=follow_up  durable_session_id=40b06ad6…
(~240s later) WARNING event=missing_response_created_timeout  pending=1
event=close ; event=retire_stale_pending
  • Both attempts used the identical bridge_key, account …7cb39f74, durable_session_id, anchor resp_0563…, and 425 resent items. Each stalled ~241s. reallocate_sticky=False.
  • The client recorded each as a terminal error and did not auto-recover.
  • A fresh client session started under the same conditions came in as kind=websocket request_stage=first_turn with no injected anchor and proceeded normally. So a recoverable path exists; the running session could not reach it.
  • This deadline/stall path is HTTP-bridge only; the WebSocket-upstream path has no equivalent deadline.

Steps to reproduce

  1. Run a long multi-turn session (codex session affinity on).
  2. Let the upstream bridge go idle long enough to be retired (about 4 minutes).
  3. Send the next turn. codex-lb does a fresh reattach with a full resend.
  4. Upstream does not emit response.created; ~240s later the turn fails with the deadline error.
  5. Retry in the same session: it reproduces identically. Restart the client (new session): it recovers.

Expected behavior

Repeated missing_response_created_timeout for a session should be recoverable without a full client restart. Under the same conditions a fresh session with no injected anchor succeeds, so the recoverable path already exists; a session that hits this should be able to reach it on its own.

Notes / scope

  • The trigger (upstream not emitting response.created) appears to be backend-side and I can't confirm its cause, so I'm not attributing that to codex-lb. Bounding the wait at 240s is good; this report is only about the behavior after the timeout, where the identical reattach is replayed on retry.
  • Related to WebSocket path renames upstream previous_response_not_found, and unlike the HTTP path does not keep the error client-recoverable #1529: same underlying loss of store:false connection continuity, different transport (HTTP-bridge vs WebSocket) and different symptom (stall vs immediate error). Both point at the same need: let the client recover without manual intervention.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions