From 1c78a02cd846bf65584464145bf8a79ee444492e Mon Sep 17 00:00:00 2001 From: George Fu Date: Tue, 16 Sep 2025 14:14:45 -0400 Subject: [PATCH] docs: update guidance on instanceof Exception checking --- supplemental-docs/ERROR_HANDLING.md | 83 ++++++++++++++++++----------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/supplemental-docs/ERROR_HANDLING.md b/supplemental-docs/ERROR_HANDLING.md index bcca66f643a8..8ac6cf11b307 100644 --- a/supplemental-docs/ERROR_HANDLING.md +++ b/supplemental-docs/ERROR_HANDLING.md @@ -11,28 +11,33 @@ The most common compilation error related to this SDK is the following: 'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint 'C'. ``` -This is due to `node_modules` nesting and duplication when handling transitive dependencies that exist at multiple different versions within a single workspace. -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. +This is due to `node_modules` nesting and duplication when handling transitive dependencies that exist at multiple +different versions within a single workspace. +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. -To remedy this, install every `@aws-sdk/client-*` package at or around the same version. +To remedy this, install every `@aws-sdk/client-*` package at or around the same version. ```json { "name": "your-app", "dependencies": { - "@aws-sdk/client-s3": "<=3.600.0", - "@aws-sdk/client-dynamodb": "<=3.600.0", - "@aws-sdk/client-lambda": "<=3.600.0", + "@aws-sdk/client-s3": "<=3.800.0", + "@aws-sdk/client-dynamodb": "<=3.800.0", + "@aws-sdk/client-lambda": "<=3.800.0" } } ``` -The `<=` version prefix means to install the greatest version number below or at the given value. This is helpful because the `@aws-sdk/*` namespace -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. +The `<=` version prefix means to install the greatest version number below or at the given value. This is helpful +because the `@aws-sdk/*` namespace +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. ## Runtime errors not related to AWS service responses -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. +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. ```ts // Example runtime error prior to request @@ -43,26 +48,29 @@ const s3 = new S3(); await s3.getObject({ Bucket: "my-bucket", Key: 5 as any, // since this should be a string, the resulting error is thrown even prior to the request being sent. - // TypeError: labelValue.split is not a function + // TypeError: labelValue.split is not a function }); ``` -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. +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. ## Errors returned by AWS services -Non-2xx responses from AWS services are surfaced to the user as thrown JavaScript `Error`s. +Non-2xx responses from AWS services are surfaced to the user as thrown JavaScript `Error`s. + +Since this SDK is generated from Smithy models, there is a conceptual notion of "unmodeled" and "modeled" errors. -Since this SDK is generated from Smithy models, there is a conceptual notion of "unmodeled" and "modeled" errors. - A modeled error or exception is an error that is declared by the service model. For example, at the bottom of the page -https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/lambda/command/CreateFunctionCommand/, there is a list of named -exceptions. These are the modeled exceptions for this Command or operation. -- An unmodeled error is one that does not appear in the list, but is thrown at runtime by the service. Some errors are unmodeled -because of incomplete modeling by the service, or because of routing layers, load balancers, security etc. that sit in front -of the service. - -Unmodeled errors are created as the default ServiceException class that exists for each AWS service, which the modeled errors also extend. -In the AWS Lambda example, it is the one at the bottom that reads: + https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/lambda/command/CreateFunctionCommand/, there is a list + of named exceptions. These are the modeled exceptions for this Command or operation. +- An unmodeled error is one that does not appear in the list, but is thrown at runtime by the service. Some errors are + unmodeled because of incomplete modeling by the service, or because of routing layers, load balancers, security etc. + that sit in front of the service. + +Unmodeled errors are created as the default ServiceException class that exists for each AWS service, which the modeled +errors also extend. In the AWS Lambda example, it is the one at the bottom that reads: + ``` LambdaServiceException - Base exception class for all service exceptions from Lambda service. ``` @@ -70,9 +78,15 @@ LambdaServiceException - Base exception class for all service exceptions from La ### Handling service returned errors As seen in the example below, SDK error handling best-practices involve the following points: -- cast the initial unknown error to the service base exception type to have type-access to the `$metadata` and `$response` fields. + +- cast the initial unknown error to the service base exception type to have type-access to the `$metadata` and + `$response` fields. - you can use switches to handle errors based on - - 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. + - the error name. + - error class `instanceof` operator calls. + - Although `instanceof` calls are in general somewhat dangerous across different packages due to NPM's module + nesting feature, the base `ServiceException` type in the AWS SDK has a `[Symbol.hasInstance]` method override, and + should work just as well as comparing by `name` property. - the `$metadata.httpStatusCode` value. - additional fields on the raw HTTP response object available at `error.$response`. @@ -98,16 +112,19 @@ try { // checking the name of the error. switch (e.name) { case CodeStorageExceededException.name: - break; case TooManyRequestsException.name: - break; case LambdaServiceException.name: default: - break; } // checking the response status code. switch (e.$metadata.httpStatusCode) { + case 500: + case 404: + case 403: + case 400: + case 200: + default: } // checking additional fields of @@ -124,14 +141,19 @@ try { ### Parsing errors arising from service responses -An additional untyped field may be present, called `error.$responseBodyText`. This is only populated when the SDK fails to parse the error response, because -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. -This can happen if for example a front-end layer throttles the request but is unaware of the underlying service data format. +An additional untyped field may be present, called `error.$responseBodyText`. This is only +populated when the SDK fails to parse the error response, because 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. +This can happen if for example a front-end layer throttles the request but is unaware of the underlying service data +format. In such cases, the error message will include the hint + ``` -Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object. +Deserialization error: to see the raw response, inspect the +hidden field {error}.$response on this object. ``` + It is not automatically logged to avoid accidental logging of sensitive data. To inspect it: @@ -150,4 +172,3 @@ try { } } ``` -