diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 7d69fa57e..d6df74d4b 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixed -- Fixed Amazon Bedrock stream error handler crashing with `TypeError: undefined is not an object (evaluating 'baseMessage.includes')` when a non-`Error` value is thrown and `JSON.stringify` returns `undefined` ([#5539](https://github.com/can1357/oh-my-pi/issues/5539)). +- Fixed Amazon Bedrock stream error handling for non-`Error` values that `JSON.stringify` cannot serialize ([#5539](https://github.com/can1357/oh-my-pi/issues/5539)). ## [16.5.2] - 2026-07-14 diff --git a/packages/ai/src/providers/amazon-bedrock.ts b/packages/ai/src/providers/amazon-bedrock.ts index 93692e8e6..6a3cf1f02 100644 --- a/packages/ai/src/providers/amazon-bedrock.ts +++ b/packages/ai/src/providers/amazon-bedrock.ts @@ -510,7 +510,12 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = ( for (const block of output.content) { if (block.type === "toolCall") clearStreamingPartialJson(block); } - const baseMessage = error instanceof Error ? error.message : (JSON.stringify(error) ?? String(error)); + let baseMessage: string; + try { + baseMessage = error instanceof Error ? error.message : (JSON.stringify(error) ?? String(error)); + } catch { + baseMessage = String(error); + } // Enrich error with thinking block diagnostics for signature-related failures let diagnostics = ""; if (baseMessage.includes("signature") || baseMessage.includes("thinking")) { diff --git a/packages/ai/test/bedrock-inference-profile.test.ts b/packages/ai/test/bedrock-inference-profile.test.ts index 75092e7f4..08314bb84 100644 --- a/packages/ai/test/bedrock-inference-profile.test.ts +++ b/packages/ai/test/bedrock-inference-profile.test.ts @@ -150,17 +150,19 @@ describe("Bedrock cross-region inference-profile geo routing", () => { }); describe("Bedrock error handling", () => { - // Regression (#5539): a non-`Error` thrown inside the stream body where - // `JSON.stringify` returns `undefined` (e.g. `undefined`, a function, a - // circular object) must not crash the catch block via `baseMessage.includes(...)`. - // The stream must close cleanly with an error result instead of an unhandled - // `TypeError: undefined is not an object (evaluating 'baseMessage.includes')`. - test("surfaces a stream error when a non-Error value is thrown", async () => { + const circular: Record = {}; + circular.self = circular; + + test.each([ + ["undefined", undefined], + ["BigInt", 1n], + ["circular object", circular], + ])("surfaces a stream error when %s is thrown", async (_name, thrown) => { const result = await streamBedrock(profileModel, userContext(), { bearerToken: "test-token", maxTokens: 16, onPayload: () => { - throw undefined; + throw thrown; }, }).result();