{"record":{"id":"13a94ef7482f6d39","repo":"can1357/oh-my-pi","slug":"anthropic-sdk-request-did-not-expose-a-stream-resp","errorCode":null,"errorMessage":"Anthropic SDK request did not expose a stream response","messagePattern":"Anthropic SDK request did not expose a stream response","errorType":"exception","errorClass":"AnthropicStreamEnvelopeError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/anthropic.ts","lineNumber":1519,"sourceCode":"\tevents: AsyncIterable<AnthropicStreamEvent>;\n\tresponse: Response;\n\trequestId: string | null;\n\trecordsRawSseEvents: boolean;\n}> {\n\tif (hasAnthropicRawResponseRequest(request)) {\n\t\tconst response = await request.asResponse();\n\t\treturn {\n\t\t\tevents: iterateAnthropicEvents(response, signal, onSseEvent),\n\t\t\tresponse,\n\t\t\trequestId: response.headers.get(\"request-id\"),\n\t\t\trecordsRawSseEvents: true,\n\t\t};\n\t}\n\tif (hasAnthropicStreamWithResponseRequest(request)) {\n\t\tconst { data, response, request_id } = await request.withResponse();\n\t\treturn { events: data, response, requestId: request_id, recordsRawSseEvents: false };\n\t}\n\tthrow new AIError.AnthropicStreamEnvelopeError(\"Anthropic SDK request did not expose a stream response\");\n}\n\nasync function* observeDecodedAnthropicSdkEvents(\n\tevents: AsyncIterable<AnthropicStreamEvent>,\n\tobserver: (event: RawSseEvent) => void,\n): AsyncGenerator<AnthropicStreamEvent> {\n\tfor await (const event of events) {\n\t\tconst data = JSON.stringify(event);\n\t\t// Reconstructed from decoded SDK event; not literal wire bytes.\n\t\tnotifyRawSseEvent(observer, { event: event.type, data, raw: [`event: ${event.type}`, `data: ${data}`] });\n\t\tyield event;\n\t}\n}\n\nconst PROVIDER_MAX_RETRIES = 10;\n\n/**\n * Flat delay between attempts when Copilot 400s a model its own `/models`","sourceCodeStart":1501,"sourceCodeEnd":1537,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/anthropic.ts#L1501-L1537","documentation":"This AnthropicStreamEnvelopeError is thrown when the SDK request promise returned by the Anthropic client does not implement the withResponse() contract the library relies on. The library needs the raw HTTP response (headers, request id) alongside the decoded event stream, so a request without this surface cannot be observed.","triggerScenarios":"Calling the streaming path with an Anthropic SDK client whose messages.create result lacks the withResponse() method (hasAnthropicStreamWithResponseRequest returns false) — typically a different/incompatible SDK version, a mock, or a non-SDK object passed where the client's request promise is expected.","commonSituations":"Pinning an older or forked @anthropic-ai/sdk that changed the return type; mocking client.messages.create with a plain AsyncIterable in tests; wrapping the client in a proxy that drops methods; using a gateway SDK that mimics but does not match the official API.","solutions":["Upgrade or align @anthropic-ai/sdk to the version this library expects so stream requests expose withResponse().","If mocking in tests, implement withResponse() returning { data, response, request_id }.","Verify the raw client instance (not a partially wrapped object) is passed to the streaming path.","Check hasAnthropicStreamWithResponseRequest expectations against the SDK's actual API surface in node_modules."],"exampleFix":"// before\nmessages: { create: async () => eventStream } // no withResponse\n\n// after\nmessages: {\n  create: async () => ({\n    [Symbol.asyncIterator]: eventStream[Symbol.asyncIterator].bind(eventStream),\n    withResponse: async () => ({ data: eventStream, response: rawResponse, request_id: \"req_1\" }),\n  }),\n}","handlingStrategy":"type-guard","validationCode":"function isStreamRequestWithResponse(req: unknown): req is { withResponse(): Promise<{ data: AsyncIterable<unknown>; response: Response; request_id?: string }> } {\n  return typeof req === \"object\" && req !== null && \"withResponse\" in req && typeof (req as { withResponse?: unknown }).withResponse === \"function\";\n}\n// check before handing the SDK request to the streaming path","typeGuard":"const request = client.messages.create(params, options);\nif (typeof (request as { withResponse?: unknown }).withResponse !== \"function\") {\n  throw new Error(\"Anthropic SDK does not expose withResponse(); upgrade @anthropic-ai/sdk.\");\n}","tryCatchPattern":"try {\n  const { events, response } = await request.withResponse();\n  return { events, response };\n} catch (err) {\n  if (err instanceof AIError.AnthropicStreamEnvelopeError && /did not expose a stream response/.test(err.message)) {\n    // fall back to a manual fetch SSE request to the messages endpoint\n  } else {\n    throw err;\n  }\n}","preventionTips":["Pin @anthropic-ai/sdk to a version range compatible with this library and test upgrades in CI.","Keep SDK mocks complete: implement withResponse(), not just the async iterator.","Avoid proxies/wrappers around the client that strip SDK request methods.","Check the SDK changelog when bumping versions for return-type changes on messages.create."],"tags":["anthropic","sdk","streaming","api-mismatch"],"backgroundTag":"sdk-api-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}