Skip to content

Commit e329689

Browse files
committed
fix(middleware-retry): defaultStrategy handles any error
The lower level stacks than throw anything to retry strategy in practice, so casting them to SdkError type is unsafe. With this change the retryStrategy will do best effort to convert the thrown any object to SdkError and then supply to retryDecider and so on. Another change is making SdkError type more general. It previously requires $fault, $metadata, which is obviously incorrect. Error thrown by SDK itself never contains these keys. So I mark them optional. Granted this is a breaking change to function interface like RetryDecider, but anyone depending it being required should already fail anyway.
1 parent 2384e24 commit e329689

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

packages/middleware-retry/src/defaultStrategy.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ describe("defaultStrategy", () => {
100100
});
101101
});
102102

103+
it("handles non-standard errors", () => {
104+
const nonStandardErrors = [undefined, "foo", { foo: "bar" }, 123, false, null];
105+
const maxAttempts = 1;
106+
const retryStrategy = new StandardRetryStrategy(() => Promise.resolve(maxAttempts));
107+
for (const error of nonStandardErrors) {
108+
next = jest.fn().mockRejectedValue(error);
109+
expect(retryStrategy.retry(next, { request: { headers: {} } } as any)).rejects.toBeInstanceOf(Error);
110+
}
111+
});
112+
103113
describe("retryDecider init", () => {
104114
it("sets defaultRetryDecider if options is undefined", () => {
105115
const retryStrategy = new StandardRetryStrategy(() => Promise.resolve(maxAttempts));

packages/middleware-retry/src/defaultStrategy.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ export class StandardRetryStrategy implements RetryStrategy {
129129
output.$metadata.totalRetryDelay = totalDelay;
130130

131131
return { response, output };
132-
} catch (err) {
132+
} catch (e) {
133+
const err = asSdkError(e);
133134
attempts++;
134135
if (this.shouldRetry(err as SdkError, attempts, maxAttempts)) {
135136
retryTokenAmount = this.retryQuota.retrieveRetryTokens(err);
@@ -154,3 +155,10 @@ export class StandardRetryStrategy implements RetryStrategy {
154155
}
155156
}
156157
}
158+
159+
const asSdkError = (error: unknown): SdkError => {
160+
if (error instanceof Error) return error;
161+
if (error instanceof Object) return Object.assign(new Error(), error);
162+
if (typeof error === "string") return new Error(error);
163+
return new Error(`AWS SDK error wrapper for ${error}`);
164+
};

packages/smithy-client/src/sdk-error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import { MetadataBearer } from "@aws-sdk/types";
22

33
import { SmithyException } from "./exception";
44

5-
export type SdkError = Error & SmithyException & MetadataBearer;
5+
export type SdkError = Error & Partial<SmithyException> & Partial<MetadataBearer>;

0 commit comments

Comments
 (0)