Skip to content

feat!: report every SSE error response with status, headers, and recoverability#311

Open
kinyoklion wants to merge 1 commit into
rlamb/sdk-2186/fdv2-data-systemfrom
rlamb/sdk-2189/sse-fallback-directive
Open

feat!: report every SSE error response with status, headers, and recoverability#311
kinyoklion wants to merge 1 commit into
rlamb/sdk-2186/fdv2-data-systemfrom
rlamb/sdk-2189/sse-fallback-directive

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Jun 24, 2026

Copy link
Copy Markdown
Member

⚠ Breaking change

The SSE client now reports recoverable error responses (e.g. 5xx) on the stream. Previously only unrecoverable responses surfaced and recoverable ones were retried silently. A consumer that treats any error from the stream as terminal will now tear down on a transient error — it must check SseHttpError.recoverable and ignore recoverable errors (the client retries those itself). UnrecoverableStatusError is removed; use SseHttpError instead.

This bumps event_source to a major (2.2.0 → 3.0.0).

What

Replaces UnrecoverableStatusError with SseHttpError, reported on the event stream for any non-200 response — recoverable or not. It carries:

  • statusCode
  • headers (always — may hold a service directive)
  • recoverable — whether the client will retry on its own (backoff) or has stopped
final class SseHttpError implements Exception {
  final int statusCode;
  final Map<String, String> headers;
  final bool recoverable;
  const SseHttpError(this.statusCode, this.headers, {required this.recoverable});
}

Why

A LaunchDarkly streaming endpoint can deliver the FDv2-to-FDv1 fallback directive (x-ld-fd-fallback) in the headers of an otherwise-retriable error response (e.g. a 500). Previously recoverable responses surfaced nothing, so that directive was invisible and the client just kept reconnecting. Now every error response is reported with its headers and a recoverable flag, and the consumer decides what to do. This keeps the client a pure transport — it reports what it saw rather than taking an injected retry policy. The browser EventSource cannot observe responses and reports nothing, as before.

Tests

state_connecting covers a recoverable error (backs off, reports recoverable: true with headers) and an unrecoverable one (goes idle, reports recoverable: false with headers).


First of a two-PR stack; the fallback behavior that consumes this is in the stacked follow-up.


Note

Medium Risk
Breaking public API rename and new stream errors on recoverable HTTP failures may affect consumers that only handled unrecoverable cases; reconnect behavior is unchanged but observability of errors increases.

Overview
Breaking: Replaces exported UnrecoverableStatusError with SseHttpError, which includes statusCode, headers, and a required recoverable flag.

Behavior: On any non-200 HTTP response during connect, the client now surfaces SseHttpError on the event stream—not only when retries stop. For recoverable statuses it still backs off and reconnects, but first emits the error (so headers like x-ld-fd-fallback are visible on retriable failures). For non-recoverable statuses it still transitions to idle and reports the same error type with recoverable: false.

Tests were updated to assert stream errors for both recoverable (e.g. 503) and unrecoverable (e.g. 401) cases, including directive headers.

Reviewed by Cursor Bugbot for commit 6bcf11f. Bugbot is set up for automated code reviews on this repo. Configure here.

@kinyoklion kinyoklion force-pushed the rlamb/sdk-2189/sse-fallback-directive branch from 306fef8 to 2343975 Compare June 24, 2026 16:12
@kinyoklion kinyoklion changed the title feat: allow vetoing SSE retry of a directive-bearing error response feat: report every SSE error response with status, headers, and recoverability Jun 24, 2026
@kinyoklion kinyoklion changed the title feat: report every SSE error response with status, headers, and recoverability feat!: report every SSE error response with status, headers, and recoverability Jun 24, 2026
@kinyoklion kinyoklion marked this pull request as ready for review June 24, 2026 16:17
@kinyoklion kinyoklion requested a review from a team as a code owner June 24, 2026 16:17
…verability

Replace UnrecoverableStatusError with SseHttpError, reported on the event
stream for any non-200 response -- recoverable or not. It carries the
status code, the response headers (which may hold a service directive),
and a recoverable flag indicating whether the client will retry on its own
(backoff) or has stopped.

BREAKING CHANGE: The SSE client now reports recoverable error responses
(e.g. 5xx) on the stream; previously only unrecoverable responses surfaced
and recoverable ones were retried silently. A consumer that treats any
error from the stream as terminal will now tear down on a transient error.
Such consumers must check SseHttpError.recoverable and ignore recoverable
errors -- the client retries those on its own. UnrecoverableStatusError is
removed; use SseHttpError (statusCode, headers, recoverable) instead.
@kinyoklion kinyoklion force-pushed the rlamb/sdk-2189/sse-fallback-directive branch from 2343975 to 6bcf11f Compare June 24, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants