can1357/oh-my-pi · error · AuthBrokerError

Auth broker stream ended before initial snapshot

Error message

Auth broker stream ended before initial snapshot

What it means

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.

Source

Thrown at packages/ai/src/auth-broker/client.ts:262

				});
			}
			const validated = snapshotStreamEventSchema(parsed);
			if (validated instanceof type.errors) {
				throw new AuthBrokerError("Auth broker stream event failed schema validation", {
					body: validated.summary,
				});
			}
			const event = validated as SnapshotStreamEvent;
			if (!sawFirstEvent) {
				sawFirstEvent = true;
				if (event.kind !== "snapshot") {
					throw new AuthBrokerError("Auth broker stream did not start with snapshot", { body: sse.data });
				}
			}
			yield event;
		}
		if (!opts.signal?.aborted) {
			throw new AuthBrokerError(
				sawFirstEvent
					? "Auth broker stream ended unexpectedly"
					: "Auth broker stream ended before initial snapshot",
				{ status: response.status },
			);
		}
	}

	/**
	 * Fetch aggregate broker usage with a timeout sized for serialized
	 * same-provider account probes.
	 */
	fetchUsage(options: { signal?: AbortSignal; maxAccountsPerProvider?: number } = {}): Promise<UsageResponse> {
		const requestedAccountCount = options.maxAccountsPerProvider;
		const accountCount =
			typeof requestedAccountCount === "number" && Number.isFinite(requestedAccountCount)
				? Math.max(1, Math.floor(requestedAccountCount))
				: 1;

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry openSnapshotStream with backoff — a one-off dropped connection is usually transient.
  2. Check broker logs for handler panics/errors immediately after the stream endpoint commits headers.
  3. Inspect network path (reverse proxy, LB) for connections accepted then dropped before data flows.
  4. Check broker resource health (file descriptors, connection limits) if it occurs under load.
  5. Fall back to fetchSnapshot() long-polling if streaming repeatedly fails to deliver an initial snapshot.

Example fix

// before
for await (const event of client.openSnapshotStream({ signal })) {
  applyEvent(event);
}

// after
try {
  for await (const event of client.openSnapshotStream({ signal })) {
    applyEvent(event);
  }
} catch (err) {
  if (!signal.aborted && err instanceof AuthBrokerError && err.message.includes("before initial snapshot")) {
    logger.warn("stream ended pre-snapshot, retrying", { status: err.status });
    await retryStreamWithBackoff(signal);
  } else {
    throw err;
  }
}
Defensive patterns

Strategy: retry

Type guard

function isEndedBeforeSnapshot(err: unknown): err is AuthBrokerError {
  return err instanceof AuthBrokerError && err.message === "Auth broker stream ended before initial snapshot";
}

Try / catch

try {
  for await (const event of client.openSnapshotStream({ signal })) {
    applyEvent(event);
  }
} catch (err) {
  if (!signal.aborted && isEndedBeforeSnapshot(err)) {
    logger.warn("stream died before initial snapshot; retrying", { status: err.status });
    await reconnectWithBackoff(signal);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e42021c12062e102. Report an issue: GitHub.