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

  1. Check signal.aborted before calling openSnapshotStream, or create a fresh AbortController for the stream
  2. Start the stream before the cancellation scope closes, or pass a long-lived signal tied to the consumer's lifetime
  3. 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

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.