Repository navigation
fix(openai): stop retrying streamed APIError events (fixes NV-9270) - #25
Merged
ChmaraX merged 1 commit intoNov 2, 2026
Conversation
openai 7.6 and newer throw a named SSE error as APIError with no HTTP status. Treat that as a provider failure, and classify it with the same helper the parser uses. Connection errors, timeouts and 5xx responses still reconnect. mapError now passes ThalamusError through, so the provider maps errors in one place. The openai test mocks spread the real module instead of listing exports.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
openai 7.6 and newer throw a named SSE
event: errorframe as anAPIErrorwith no HTTP status, before Thalamus's parser sees it (openai/openai-node#2409).isTransientStreamErroronly stopped on a 4xx status, so a rate-limit or invalid-key error reported in the stream was treated as a dropped connection. Afterresponse.created, the provider resumed the failed response throughGET /responses/{id}up to 3 times before it failed.What changed
isTransientStreamErrortreats anAPIErrorwith no status as terminal.APIConnectionErrorandAPIConnectionTimeoutError, which also have no status, are checked first and still reconnect. 5xx responses also still reconnect.classifyOpenAIFailureis now the one code/message →ThalamusErrorclassifier. The parser'scase "error"and the provider'smapErrorboth use it.mapErrorpasses aThalamusErrorthrough unchanged and returnsThalamusError. The two inlineinstanceof ThalamusError ? err : mapError(...)copies in the provider now callmapErrordirectly.vi.mock("openai")factories spread the real module ({ ...actual, default: MockOpenAI }), so new SDK imports in the provider don't need test edits.Scope
mapOpenAIErrornow returns the narrowerThalamusErrortype.case "error"path stays. The edge observer and older SDKs still reach it, and it is still covered inopenai.errors.test.ts.openaidev dependency pin to^7.44.0already landed in refactor(openai): sign Bedrock with the SDK provider fixes NV-9271 #24, so this PR doesn't touchpackage.jsonor the lockfile.Blast radius
On openai 7.6 and newer, an in-stream OpenAI error now fails the run immediately with the mapped error, such as
ProviderRateLimitErrororProviderAuthError, and makes no reconnect requests. A mid-streamserver_errorframe now also fails the run instead of resuming. That matches how the parser already handled it on openai 6.x. Novu doesn't construct this provider today.Verification
pnpm typecheck,pnpm test(261 tests), andpnpm buildpass. Biome on tracked files finds only the existing warnings.openai.streamed-error.test.tsruns a real openai client against a fakefetch. Rate-limit and invalid-keyevent: errorframes fail with the mapped error and make noGET /responses/{id}calls. A dropped socket afterresponse.createdstill resumes.openai.reconnect.test.tsmake the first resume request fail withAPIConnectionError,APIConnectionTimeoutError, or a 503, and the send still completes. With theAPIConnectionErrorcheck removed, the two connection-error cases fail.

Confidence Score: 5/5 
The PR appears safe to merge; no actionable issues were found.Summary
Stops reconnecting after streamed provider errors while keeping retries for connection failures and HTTP 5xx errors.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A["Stream throws"] --> B{"Connection error?"} B -->|Yes| C["Keep reconnect eligible"] B -->|No| D{"Statusless APIError or HTTP 4xx?"} D -->|Yes| E["Stop reconnecting"] D -->|No| C E --> F["Map error and fail send"]Reviews (1) · Last reviewed commit: "fix(openai): stop retrying streamed APIE..." · Reviewed by Greptile