Skip to content

Commit

Permalink
fix(middleware-serde): handle unwritable error message (#1512)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhe authored Jan 24, 2025
1 parent fbe3c04 commit f5d0bac
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-trees-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@smithy/middleware-serde": patch
---

handle unwritable error.message field
40 changes: 40 additions & 0 deletions packages/middleware-serde/src/deserializerMiddleware.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,44 @@ describe("deserializerMiddleware", () => {
expect(e.$response.body).toEqual("oh no");
}
});

it("handles unwritable error.message", async () => {
const exception = Object.assign({}, mockNextResponse.response, {
$response: {
body: "",
},
$responseBodyText: "oh no",
});

Object.defineProperty(exception, "message", {
set() {
throw new Error("may not call setter");
},
get() {
return "MockException";
},
});

const sink = vi.fn();

mockDeserializer.mockReset();
mockDeserializer.mockRejectedValueOnce(exception);
try {
await deserializerMiddleware(mockOptions, mockDeserializer)(mockNext, {
logger: {
debug: sink,
info: sink,
warn: sink,
error: sink,
},
})(mockArgs);
fail("DeserializerMiddleware should throw");
} catch (e) {
expect(sink).toHaveBeenCalledWith(
`Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`
);
expect(e.message).toEqual("MockException");
expect(e.$response.body).toEqual("oh no");
}
});
});
14 changes: 12 additions & 2 deletions packages/middleware-serde/src/deserializerMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DeserializeHandlerArguments,
DeserializeHandlerOutput,
DeserializeMiddleware,
HandlerExecutionContext,
ResponseDeserializer,
SerdeContext,
SerdeFunctions,
Expand All @@ -16,7 +17,7 @@ export const deserializerMiddleware =
options: SerdeFunctions,
deserializer: ResponseDeserializer<any, any, CommandSerdeContext>
): DeserializeMiddleware<Input, Output> =>
(next: DeserializeHandler<Input, Output>): DeserializeHandler<Input, Output> =>
(next: DeserializeHandler<Input, Output>, context: HandlerExecutionContext): DeserializeHandler<Input, Output> =>
async (args: DeserializeHandlerArguments<Input>): Promise<DeserializeHandlerOutput<Output>> => {
const { response } = await next(args);
try {
Expand All @@ -41,7 +42,16 @@ export const deserializerMiddleware =
if (!("$metadata" in error)) {
// only apply this to non-ServiceException.
const hint = `Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;
error.message += "\n " + hint;
try {
error.message += "\n " + hint;
} catch (e) {
// Error with an unwritable message (strict mode getter with no setter).
if (!context.logger || context.logger?.constructor?.name === "NoOpLogger") {
console.warn(hint);
} else {
context.logger?.warn?.(hint);
}
}

if (typeof error.$responseBodyText !== "undefined") {
// if $responseBodyText was collected by the error parser, assign it to
Expand Down

0 comments on commit f5d0bac

Please sign in to comment.