Skip to content

Commit 23503c6

Browse files
authored
docs: add ERROR_HANDLING.md supplemental (#6454)
1 parent 31a992a commit 23503c6

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

supplemental-docs/ERROR_HANDLING.md

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Error Handling
2+
3+
## Compilation errors
4+
5+
The most common compilation error related to this SDK is the following:
6+
7+
```
8+
error TS2345: Argument of type 'X' is not assignable to parameter of type 'Y'.
9+
The types of 'Z' are incompatible between these types.
10+
... many lines of tracing ...
11+
'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint 'C'.
12+
```
13+
14+
This is due to `node_modules` nesting and duplication when handling transitive dependencies that exist at multiple different versions within a single workspace.
15+
Most commonly, this is caused by an application installing different versions of various SDK clients that all depend on `@smithy/types` or `@aws-sdk/types`, but at different versions.
16+
17+
To remedy this, install every `@aws-sdk/client-*` package at or around the same version.
18+
19+
```json
20+
{
21+
"name": "your-app",
22+
"dependencies": {
23+
"@aws-sdk/client-s3": "<=3.600.0",
24+
"@aws-sdk/client-dynamodb": "<=3.600.0",
25+
"@aws-sdk/client-lambda": "<=3.600.0",
26+
}
27+
}
28+
```
29+
30+
The `<=` version prefix means to install the greatest version number below or at the given value. This is helpful because the `@aws-sdk/*` namespace
31+
only releases package version updates when there are changes, but the version number in the monorepo increments every day. Not every minor version number exists for each package.
32+
33+
## Runtime errors not related to AWS service responses
34+
35+
You may encounter SDK errors before a request is made. Since we provide a TypeScript API, we do not runtime typecheck every value, since that would increase application size.
36+
37+
```ts
38+
// Example runtime error prior to request
39+
import { S3 } from "@aws-sdk/client-s3";
40+
41+
const s3 = new S3();
42+
43+
await s3.getObject({
44+
Bucket: "my-bucket",
45+
Key: 5 as any, // since this should be a string, the resulting error is thrown even prior to the request being sent.
46+
// TypeError: labelValue.split is not a function
47+
});
48+
```
49+
50+
In such cases, refer to the API documentation or TypeScript declarations, or create an [issue report](https://github.com/aws/aws-sdk-js-v3/issues) for additional assistance.
51+
52+
## Errors returned by AWS services
53+
54+
Non-2xx responses from AWS services are surfaced to the user as thrown JavaScript `Error`s.
55+
56+
Since this SDK is generated from Smithy models, there is a conceptual notion of "unmodeled" and "modeled" errors.
57+
- A modeled error or exception is an error that is declared by the service model. For example, at the bottom of the page
58+
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/lambda/command/CreateFunctionCommand/, there is a list of named
59+
exceptions. These are the modeled exceptions for this Command or operation.
60+
- An unmodeled error is one that does not appear in the list, but is thrown at runtime by the service. Some errors are unmodeled
61+
because of incomplete modeling by the service, or because of routing layers, load balancers, security etc. that sit in front
62+
of the service.
63+
64+
Unmodeled errors are created as the default ServiceException class that exists for each AWS service, which the modeled errors also extend.
65+
In the AWS Lambda example, it is the one at the bottom that reads:
66+
```
67+
LambdaServiceException - Base exception class for all service exceptions from Lambda service.
68+
```
69+
70+
### Handling service returned errors
71+
72+
As seen in the example below, SDK error handling best-practices involve the following points:
73+
- cast the initial unknown error to the service base exception type to have type-access to the `$metadata` and `$response` fields.
74+
- you can use switches to handle errors based on
75+
- the error name. `instanceof` checks are not recommended for error handling due to the possibility of prototype mismatch caused by nesting or other forms of copying/duplication.
76+
- the `$metadata.httpStatusCode` value.
77+
- additional fields on the raw HTTP response object available at `error.$response`.
78+
79+
```ts
80+
// Example: service error handling
81+
import { Lambda } from "@aws-sdk/client-lambda";
82+
import { CodeStorageExceededException, LambdaServiceException, TooManyRequestsException } from "@aws-sdk/client-lambda";
83+
84+
const lambda = new Lambda({});
85+
86+
// function to check and typecast the thrown
87+
// error to the service base error type.
88+
function isSdkServiceError(e: unknown): e is LambdaServiceException {
89+
return !!(e as LambdaServiceException)?.$metadata;
90+
}
91+
92+
try {
93+
await lambda.createFunction({
94+
/* ... */
95+
});
96+
} catch (e: unknown) {
97+
if (isSdkServiceError(e)) {
98+
// checking the name of the error.
99+
switch (e.name) {
100+
case CodeStorageExceededException.name:
101+
break;
102+
case TooManyRequestsException.name:
103+
break;
104+
case LambdaServiceException.name:
105+
default:
106+
break;
107+
}
108+
109+
// checking the response status code.
110+
switch (e.$metadata.httpStatusCode) {
111+
}
112+
113+
// checking additional fields of
114+
// the raw HTTP response.
115+
switch (e.$response?.headers["header-name"]) {
116+
}
117+
118+
if ((e as any).$responseBodyText) {
119+
console.debug((e as any).$responseBodyText);
120+
}
121+
}
122+
}
123+
```
124+
125+
### Parsing errors arising from service responses
126+
127+
An additional untyped field may be present, called `error.$responseBodyText`. This is only populated when the SDK fails to parse the error response, because
128+
it is in an unexpected format. For example, if the service model says the service data format is JSON, but the error body is plaintext.
129+
This can happen if for example a front-end layer throttles the request but is unaware of the underlying service data format.
130+
131+
In such cases, the error message will include the hint
132+
```
133+
Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.
134+
```
135+
It is not automatically logged to avoid accidental logging of sensitive data.
136+
137+
To inspect it:
138+
139+
```ts
140+
// using S3 as an example, but applicable to any service.
141+
import { S3 } from "@aws-sdk/client-s3";
142+
143+
const client = new S3();
144+
145+
try {
146+
await client.listBuckets();
147+
} catch (e: any) {
148+
if (e.$responseBodyText) {
149+
console.debug(e.$responseBodyText);
150+
}
151+
}
152+
```
153+

0 commit comments

Comments
 (0)