can1357/oh-my-pi · warning · AuthBrokerError
Auth broker request aborted
Error message
Auth broker request aborted
What it means
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.
Source
Thrown at packages/ai/src/auth-broker/client.ts:205
/**
* Subscribe to the broker's SSE snapshot stream. The first frame is always
* a full `snapshot`; subsequent frames are `entry` upserts / refreshes or
* `removed` deletes. Caller controls lifecycle via `opts.signal`.
*
* Throws {@link AuthBrokerStreamUnsupportedError} when the broker responds
* 404 — older brokers predate this endpoint and the caller should fall back
* to long-polling for the remainder of its lifetime.
*/
async *openSnapshotStream(opts: { signal?: AbortSignal } = {}): AsyncGenerator<SnapshotStreamEvent> {
const url = `${this.#baseUrl}/v1/snapshot/stream`;
const headers: Record<string, string> = {
Accept: "text/event-stream",
Authorization: `Bearer ${this.#token}`,
[AUTH_BROKER_CAPABILITIES_HEADER]: AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES,
};
if (opts.signal?.aborted) {
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
}
// No timeout: this connection is intentionally long-lived. Caller's signal
// is the only cancel path.
const response = await this.#fetch(url, { method: "GET", headers, signal: opts.signal });
if (response.status === 404) {
// Drain the body so the socket can be reused; tiny payload.
await response.text().catch(() => {});
throw new AuthBrokerStreamUnsupportedError();
}
if (!response.ok) {
const text = await response.text().catch(() => "");
throw new AuthBrokerError(`Auth broker stream failed: ${response.status} ${response.statusText}`, {
status: response.status,
body: text,
});
}
if (!response.body) {
throw new AuthBrokerError("Auth broker stream response had no body", { status: response.status });View on GitHub (pinned to 9690622007)
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
Example fix
// before: already-aborted signal
await client.openSnapshotStream({ signal: doneController.signal })
// after: fresh controller for the stream lifetime
const controller = new AbortController()
await client.openSnapshotStream({ signal: controller.signal }) Defensive patterns
Strategy: validation
Validate before calling
if (signal?.aborted) {
// skip opening the stream entirely
return; // or use signal.reason to decide whether this is expected cancellation
} Type guard
function canOpenStream(opts: { signal?: AbortSignal }): boolean {
return !opts.signal?.aborted;
} Try / catch
try {
const stream = await client.openSnapshotStream({ signal });
} catch (err) {
if (err instanceof AuthBrokerError && err.message === "Auth broker request aborted") {
return; // expected cancellation, not a failure
}
throw err;
} Prevention
- 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
When it happens
Trigger: Calling openSnapshotStream with an AbortSignal that is already aborted (e.g. the caller's context was cancelled before subscribing to the stream).
Common situations: 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.
Related errors
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/249fdc7aa42dfe5b.
Report an issue: GitHub.