{"record":{"id":"e42021c12062e102","repo":"can1357/oh-my-pi","slug":"auth-broker-stream-ended-before-initial-snapshot","errorCode":null,"errorMessage":"Auth broker stream ended before initial snapshot","messagePattern":"Auth broker stream ended before initial snapshot","errorType":"exception","errorClass":"AuthBrokerError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/auth-broker/client.ts","lineNumber":262,"sourceCode":"\t\t\t\t});\n\t\t\t}\n\t\t\tconst validated = snapshotStreamEventSchema(parsed);\n\t\t\tif (validated instanceof type.errors) {\n\t\t\t\tthrow new AuthBrokerError(\"Auth broker stream event failed schema validation\", {\n\t\t\t\t\tbody: validated.summary,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst event = validated as SnapshotStreamEvent;\n\t\t\tif (!sawFirstEvent) {\n\t\t\t\tsawFirstEvent = true;\n\t\t\t\tif (event.kind !== \"snapshot\") {\n\t\t\t\t\tthrow new AuthBrokerError(\"Auth broker stream did not start with snapshot\", { body: sse.data });\n\t\t\t\t}\n\t\t\t}\n\t\t\tyield event;\n\t\t}\n\t\tif (!opts.signal?.aborted) {\n\t\t\tthrow new AuthBrokerError(\n\t\t\t\tsawFirstEvent\n\t\t\t\t\t? \"Auth broker stream ended unexpectedly\"\n\t\t\t\t\t: \"Auth broker stream ended before initial snapshot\",\n\t\t\t\t{ status: response.status },\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Fetch aggregate broker usage with a timeout sized for serialized\n\t * same-provider account probes.\n\t */\n\tfetchUsage(options: { signal?: AbortSignal; maxAccountsPerProvider?: number } = {}): Promise<UsageResponse> {\n\t\tconst requestedAccountCount = options.maxAccountsPerProvider;\n\t\tconst accountCount =\n\t\t\ttypeof requestedAccountCount === \"number\" && Number.isFinite(requestedAccountCount)\n\t\t\t\t? Math.max(1, Math.floor(requestedAccountCount))\n\t\t\t\t: 1;","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth-broker/client.ts#L244-L280","documentation":"If the SSE event loop ends without ever receiving a single event while the caller's AbortSignal is not aborted, openSnapshotStream throws \"Auth broker stream ended before initial snapshot\" (client.ts:261-268). The stream never produced its mandatory initial snapshot, so the consumer has no credential state at all; the connection was accepted (HTTP 200, correct content-type) but terminated before any data frame arrived.","triggerScenarios":"Calling openSnapshotStream() and the server sends response headers (200 text/event-stream) then closes the body — e.g. broker handler errors immediately after writing headers, connection reset before the first frame, or empty SSE stream termination — with opts.signal never aborted.","commonSituations":"Broker crashes or panics inside the stream handler right after committing response headers; proxy accepting the upgrade but failing to reach the upstream (half-open connection); TLS/keepalive negotiation dropping the connection; broker under load shedding connections it accepted but cannot serve.","solutions":["Retry openSnapshotStream with backoff — a one-off dropped connection is usually transient.","Check broker logs for handler panics/errors immediately after the stream endpoint commits headers.","Inspect network path (reverse proxy, LB) for connections accepted then dropped before data flows.","Check broker resource health (file descriptors, connection limits) if it occurs under load.","Fall back to fetchSnapshot() long-polling if streaming repeatedly fails to deliver an initial snapshot."],"exampleFix":"// before\nfor await (const event of client.openSnapshotStream({ signal })) {\n  applyEvent(event);\n}\n\n// after\ntry {\n  for await (const event of client.openSnapshotStream({ signal })) {\n    applyEvent(event);\n  }\n} catch (err) {\n  if (!signal.aborted && err instanceof AuthBrokerError && err.message.includes(\"before initial snapshot\")) {\n    logger.warn(\"stream ended pre-snapshot, retrying\", { status: err.status });\n    await retryStreamWithBackoff(signal);\n  } else {\n    throw err;\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isEndedBeforeSnapshot(err: unknown): err is AuthBrokerError {\n  return err instanceof AuthBrokerError && err.message === \"Auth broker stream ended before initial snapshot\";\n}","tryCatchPattern":"try {\n  for await (const event of client.openSnapshotStream({ signal })) {\n    applyEvent(event);\n  }\n} catch (err) {\n  if (!signal.aborted && isEndedBeforeSnapshot(err)) {\n    logger.warn(\"stream died before initial snapshot; retrying\", { status: err.status });\n    await reconnectWithBackoff(signal);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Retry with exponential backoff — first-frame drops are usually transient.","Check broker healthz() before opening the stream to avoid connecting to a sick instance.","Alert on broker panics/errors inside the stream handler.","Keep a fetchSnapshot() long-poll fallback ready when streaming repeatedly fails."],"tags":["sse","empty-stream","connection-drop","auth-broker","streaming"],"backgroundTag":"sse-stream-disconnected","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}