From d600cce75b0b00f4403ffe6130133a8c2802dad2 Mon Sep 17 00:00:00 2001 From: roboomp Date: Wed, 15 Jul 2026 00:49:22 +0000 Subject: [PATCH] fix(amazon-bedrock): handled stringify exceptions Guard diagnostic JSON serialization so circular objects and BigInt values cannot escape the provider catch block. Expanded the regression coverage to undefined, BigInt, and circular thrown values. Fixes #5539 --- packages/ai/CHANGELOG.md | 2 +- packages/ai/src/providers/amazon-bedrock.ts | 7 ++++++- .../ai/test/bedrock-inference-profile.test.ts | 16 +++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) 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();