{"record":{"id":"c31be79be25dc0ed","repo":"can1357/oh-my-pi","slug":"authbrokerstreamunsupportederror","errorCode":null,"errorMessage":"AuthBrokerStreamUnsupportedError","messagePattern":"AuthBrokerStreamUnsupportedError","errorType":"exception","errorClass":"AuthBrokerStreamUnsupportedError","httpStatus":404,"severity":"warning","filePath":"packages/ai/src/auth-broker/client.ts","lineNumber":213,"sourceCode":"\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 });\n\t\t}\n\t\tconst contentType = response.headers.get(\"content-type\")?.toLowerCase();\n\t\tif (contentType?.split(\";\", 1)[0].trim() !== \"text/event-stream\") {\n\t\t\tawait response.body.cancel().catch(() => {});\n\t\t\tthrow new AuthBrokerError(\"Auth broker stream returned non-SSE response\", {\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: contentType ?? \"\",\n\t\t\t});","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/auth-broker/client.ts#L195-L231","documentation":"The auth broker stream endpoint returned HTTP 404, meaning this broker deployment does not support the SSE snapshot-stream endpoint. The client drains the tiny body (to reuse the socket) and throws AuthBrokerStreamUnsupportedError so callers can fall back to polling fetchSnapshot instead of treating it as a hard failure.","triggerScenarios":"openSnapshotStream receives a 404 from the broker's stream URL — an older broker without the streaming endpoint, a reverse proxy stripping the route, or a wrong base URL that routes to a server lacking the endpoint.","commonSituations":"Broker and client version mismatch after a client upgrade; load balancer in front of brokers with mixed versions; AUTH_BROKER_URL pointing at a legacy gateway.","solutions":["Catch AuthBrokerStreamUnsupportedError and fall back to polling fetchSnapshot (the intended contract)","Upgrade the auth broker deployment to a version with the stream endpoint","Verify the broker base URL routes to the current broker service, not a legacy gateway","Check reverse-proxy/load-balancer routing rules for the stream path"],"exampleFix":"// before: assuming stream always exists\nconst stream = await client.openSnapshotStream({ signal })\n// after: fallback to polling\ntry {\n  const stream = await client.openSnapshotStream({ signal })\n} catch (e) {\n  if (e instanceof AuthBrokerStreamUnsupportedError) startPolling(client)\n  else throw e\n}","handlingStrategy":"fallback","validationCode":"// feature-detect: probe the stream endpoint once and remember support\nlet streamSupported: boolean | null = null;\nif (streamSupported === false) startPolling(client); else openStreamWithFallback();","typeGuard":"function isStreamUnsupported(err: unknown): err is AuthBrokerStreamUnsupportedError {\n  return err instanceof AuthBrokerStreamUnsupportedError;\n}","tryCatchPattern":"try {\n  const stream = await client.openSnapshotStream({ signal });\n  consume(stream);\n} catch (err) {\n  if (err instanceof AuthBrokerStreamUnsupportedError) {\n    startPolling(client); // graceful degradation to fetchSnapshot polling\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always handle AuthBrokerStreamUnsupportedError with a polling fallback","Upgrade the broker deployment to enable the SSE stream endpoint","Check load balancer/proxy routing for the stream path on 404s","Track broker capability headers to detect support before subscribing"],"tags":["network","http-404","auth-broker","feature-detection"],"backgroundTag":"endpoint-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}