{"record":{"id":"249fdc7aa42dfe5b","repo":"can1357/oh-my-pi","slug":"auth-broker-request-aborted","errorCode":null,"errorMessage":"Auth broker request aborted","messagePattern":"Auth broker request aborted","errorType":"exception","errorClass":"AuthBrokerError","httpStatus":null,"severity":"warning","filePath":"packages/ai/src/auth-broker/client.ts","lineNumber":205,"sourceCode":"\n\t/**\n\t * Subscribe to the broker's SSE snapshot stream. The first frame is always\n\t * a full `snapshot`; subsequent frames are `entry` upserts / refreshes or\n\t * `removed` deletes. Caller controls lifecycle via `opts.signal`.\n\t *\n\t * Throws {@link AuthBrokerStreamUnsupportedError} when the broker responds\n\t * 404 — older brokers predate this endpoint and the caller should fall back\n\t * to long-polling for the remainder of its lifetime.\n\t */\n\tasync *openSnapshotStream(opts: { signal?: AbortSignal } = {}): AsyncGenerator<SnapshotStreamEvent> {\n\t\tconst url = `${this.#baseUrl}/v1/snapshot/stream`;\n\t\tconst headers: Record<string, string> = {\n\t\t\tAccept: \"text/event-stream\",\n\t\t\tAuthorization: `Bearer ${this.#token}`,\n\t\t\t[AUTH_BROKER_CAPABILITIES_HEADER]: AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES,\n\t\t};\n\t\tif (opts.signal?.aborted) {\n\t\t\tthrow new AuthBrokerError(\"Auth broker request aborted\", { cause: opts.signal.reason });\n\t\t}\n\t\t// No timeout: this connection is intentionally long-lived. Caller's signal\n\t\t// is the only cancel path.\n\t\tconst response = await this.#fetch(url, { method: \"GET\", headers, signal: opts.signal });\n\t\tif (response.status === 404) {\n\t\t\t// Drain the body so the socket can be reused; tiny payload.\n\t\t\tawait response.text().catch(() => {});\n\t\t\tthrow new AuthBrokerStreamUnsupportedError();\n\t\t}\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\tthrow new AuthBrokerError(`Auth broker stream failed: ${response.status} ${response.statusText}`, {\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: text,\n\t\t\t});\n\t\t}\n\t\tif (!response.body) {\n\t\t\tthrow new AuthBrokerError(\"Auth broker stream response had no body\", { status: response.status });","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth-broker/client.ts#L187-L223","documentation":"openSnapshotStream opens a long-lived SSE connection to the auth broker. Before issuing the request it checks opts.signal; if already aborted it throws AuthBrokerError(\"Auth broker request aborted\") with the signal's reason as cause, avoiding a doomed fetch.","triggerScenarios":"Calling openSnapshotStream with an AbortSignal that is already aborted (e.g. the caller's context was cancelled before subscribing to the stream).","commonSituations":"Race between session shutdown and starting the snapshot stream; passing a signal from a completed request scope; calling iter() after the owning operation was cancelled.","solutions":["Check signal.aborted before calling openSnapshotStream, or create a fresh AbortController for the stream","Start the stream before the cancellation scope closes, or pass a long-lived signal tied to the consumer's lifetime","Handle AuthBrokerError and treat it as normal cancellation if your flow aborts frequently"],"exampleFix":"// before: already-aborted signal\nawait client.openSnapshotStream({ signal: doneController.signal })\n// after: fresh controller for the stream lifetime\nconst controller = new AbortController()\nawait client.openSnapshotStream({ signal: controller.signal })","handlingStrategy":"validation","validationCode":"if (signal?.aborted) {\n  // skip opening the stream entirely\n  return; // or use signal.reason to decide whether this is expected cancellation\n}","typeGuard":"function canOpenStream(opts: { signal?: AbortSignal }): boolean {\n  return !opts.signal?.aborted;\n}","tryCatchPattern":"try {\n  const stream = await client.openSnapshotStream({ signal });\n} catch (err) {\n  if (err instanceof AuthBrokerError && err.message === \"Auth broker request aborted\") {\n    return; // expected cancellation, not a failure\n  }\n  throw err;\n}","preventionTips":["Pass a signal whose lifetime matches the stream consumer, not a short-lived request scope","Check signal.aborted before starting long-lived subscriptions","Create a fresh AbortController per stream instead of reusing cancelled ones","Treat this error as cancellation telemetry, not a failure metric"],"tags":["cancellation","abort","auth-broker","streaming"],"backgroundTag":"request-aborted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}