Summary
When a Response created with background: true, stream: true, store: true has its stream aborted at the very first event (response.created, before generation begins / before the response reaches in_progress), the response is left in queued indefinitely and never proceeds to a terminal state. Neither polling (GET /v1/responses/{id}) nor reconnecting (GET /v1/responses/{id}?stream=true&starting_after=0) revives it; it is not cancelled, it simply sits in queued (observed ≥10 minutes).
A disconnect even ~2 seconds later (still queued, zero output produced), or mid-generation (in_progress), recovers fine and completes. So the stuck state appears only when the disconnect coincides almost exactly with response creation.
This contradicts the documented behavior that a dropped background response “continues running and you can reconnect,” and the polling example which shows background responses progressing to completion asynchronously without a held connection.
Environment
- API: Responses API (
/v1/responses) - Model:
gpt-5.4 - Request:
background: true, stream: true, store: true(store: trueset; required for background per the docs’ Limits #1 — this is the documented resumable-streaming configuration, not a stateless request)
What I’m doing (context)
A multi-stage ingestion pipeline that streams each model call live to the user. The server is serverless, so a process can die mid-call; I want a fresh invocation to reattach to the in-progress response and finish it rather than re-issuing (and re-paying for) the request — exactly the “Streaming a background response” pattern (create with background+stream, reconnect with starting_after).
Reproduction — the failing case
POST /v1/responseswith{ model, input, background: true, stream: true, store: true }; begin consuming the SSE stream.- The instant the first event (
response.created) is received, abort the request (e.g.AbortController.abort()in the stream handler) — before anyresponse.output_text.deltaevents arrive. The response isqueuedat this point. - Attempt recovery:
- Poll
GET /v1/responses/{id}every ~2s → staysqueuedfor 2+ minutes; never advances toin_progress. - Reconnect
GET /v1/responses/{id}?stream=true&starting_after=0→ hangs with no further events (no terminal event) for 10+ minutes.
- Poll
- The response never becomes
cancelled; it remainsqueued.
(Reproduced reliably across multiple runs when the abort fires synchronously on response.created.)
Contrast — cases that recover correctly
- Abort ~2s after creation, still
queued, 0 output deltas → advances toin_progress(~t+5s) andcompleted(~t+10s). - Abort mid-generation (~160
deltaevents received, statusin_progress) →completed~5s after abort. - Fully consumed stream (no disconnect) →
completedin ~5s.
Example response ids that recovered (note ~10-minute background retention, so these may have expired by the time you look — happy to generate fresh ones or share a script):
- mid-generation abort → completed:
resp_0cec8df6418419c9006a208fbf941881928bc8d35fd1420ec9 - ~2s / queued abort → completed:
resp_0c46ae55b0480142006a20923de250819d844f92e359ba7ed8
Expected vs. actual
- Expected: per “if your connection drops, the response continues running and you can reconnect” and the async polling example, a created background response should proceed to a terminal state regardless of when (or whether) the client disconnects.
- Actual: a near-instant disconnect at
response.createdparks the response inqueuedpermanently (≥10 min observed); polling never advances it and astream=true&starting_after=0reconnect hangs.
Questions
- Is a
background: true, stream: trueresponse expected to keep running if the client disconnects atresponse.created, before it reachesin_progress? Is there a minimum commit/engagement window before background execution is guaranteed? - Should
GET /v1/responses/{id}polling eventually advance such a response, or is it permanently stuck once orphaned at creation? - Is
?stream=true&starting_after=0a valid reconnect cursor, and should reconnecting to a stuck-queuedresponse return/terminate rather than hang indefinitely with no events? - Is this behavior model-dependent?
Happy to share exact request payloads, fresh response ids, or a minimal repro script.