diff --git a/packages/normalization-core/src/error-coercion.test.ts b/packages/normalization-core/src/error-coercion.test.ts index fc543fb6fafe..f2025c5bffaa 100644 --- a/packages/normalization-core/src/error-coercion.test.ts +++ b/packages/normalization-core/src/error-coercion.test.ts @@ -55,9 +55,21 @@ describe("formatErrorMessage", () => { expect(format(new Error("request failed", { cause: { status: 429 } }))).toBe( "request failed | status=429 code=unknown", ); + // A non-Error cause carrying recognized status/code fields alongside extra + // keys used to be dropped entirely: formatStatusAndCode returns undefined + // for any object with keys beyond status/code, and the cause-chain branch + // had no stringifyUnknown fallback (unlike the top-level branch). The + // structured detail now survives instead of being swallowed. expect(format(new Error("request failed", { cause: { statusCode: 429 } }))).toBe( - "request failed", + 'request failed | {"statusCode":429}', ); + expect( + format( + new Error("request failed", { + cause: { status: 503, code: "UNAVAILABLE", requestId: "abc" }, + }), + ), + ).toBe('request failed | {"status":503,"code":"UNAVAILABLE","requestId":"abc"}'); }); it("stringifies primitives and circular records without throwing", () => { diff --git a/packages/normalization-core/src/error-coercion.ts b/packages/normalization-core/src/error-coercion.ts index c96cc060e2b7..79c397f9011c 100644 --- a/packages/normalization-core/src/error-coercion.ts +++ b/packages/normalization-core/src/error-coercion.ts @@ -117,7 +117,10 @@ export function formatErrorMessage(value: unknown, options: FormatErrorMessageOp appendCauseMessage(cause); break; } else { - appendCauseMessage(formatStatusAndCode(cause)); + // Mirror the top-level branch: an object cause with keys beyond + // status/code makes formatStatusAndCode return undefined, so fall + // back to stringifyUnknown rather than dropping the cause entirely. + appendCauseMessage(formatStatusAndCode(cause) ?? stringifyUnknown(cause)); break; } }