Skip to content

Commit f5d0bac

Browse files
authored
fix(middleware-serde): handle unwritable error message (#1512)
1 parent fbe3c04 commit f5d0bac

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

.changeset/brave-trees-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/middleware-serde": patch
3+
---
4+
5+
handle unwritable error.message field

packages/middleware-serde/src/deserializerMiddleware.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,44 @@ describe("deserializerMiddleware", () => {
9999
expect(e.$response.body).toEqual("oh no");
100100
}
101101
});
102+
103+
it("handles unwritable error.message", async () => {
104+
const exception = Object.assign({}, mockNextResponse.response, {
105+
$response: {
106+
body: "",
107+
},
108+
$responseBodyText: "oh no",
109+
});
110+
111+
Object.defineProperty(exception, "message", {
112+
set() {
113+
throw new Error("may not call setter");
114+
},
115+
get() {
116+
return "MockException";
117+
},
118+
});
119+
120+
const sink = vi.fn();
121+
122+
mockDeserializer.mockReset();
123+
mockDeserializer.mockRejectedValueOnce(exception);
124+
try {
125+
await deserializerMiddleware(mockOptions, mockDeserializer)(mockNext, {
126+
logger: {
127+
debug: sink,
128+
info: sink,
129+
warn: sink,
130+
error: sink,
131+
},
132+
})(mockArgs);
133+
fail("DeserializerMiddleware should throw");
134+
} catch (e) {
135+
expect(sink).toHaveBeenCalledWith(
136+
`Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`
137+
);
138+
expect(e.message).toEqual("MockException");
139+
expect(e.$response.body).toEqual("oh no");
140+
}
141+
});
102142
});

packages/middleware-serde/src/deserializerMiddleware.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
DeserializeHandlerArguments,
44
DeserializeHandlerOutput,
55
DeserializeMiddleware,
6+
HandlerExecutionContext,
67
ResponseDeserializer,
78
SerdeContext,
89
SerdeFunctions,
@@ -16,7 +17,7 @@ export const deserializerMiddleware =
1617
options: SerdeFunctions,
1718
deserializer: ResponseDeserializer<any, any, CommandSerdeContext>
1819
): DeserializeMiddleware<Input, Output> =>
19-
(next: DeserializeHandler<Input, Output>): DeserializeHandler<Input, Output> =>
20+
(next: DeserializeHandler<Input, Output>, context: HandlerExecutionContext): DeserializeHandler<Input, Output> =>
2021
async (args: DeserializeHandlerArguments<Input>): Promise<DeserializeHandlerOutput<Output>> => {
2122
const { response } = await next(args);
2223
try {
@@ -41,7 +42,16 @@ export const deserializerMiddleware =
4142
if (!("$metadata" in error)) {
4243
// only apply this to non-ServiceException.
4344
const hint = `Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;
44-
error.message += "\n " + hint;
45+
try {
46+
error.message += "\n " + hint;
47+
} catch (e) {
48+
// Error with an unwritable message (strict mode getter with no setter).
49+
if (!context.logger || context.logger?.constructor?.name === "NoOpLogger") {
50+
console.warn(hint);
51+
} else {
52+
context.logger?.warn?.(hint);
53+
}
54+
}
4555

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

0 commit comments

Comments
 (0)