aws_lambda_nodejs: @smithy/service-error-classification Missing in Lambda 22_X Environment
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 74
Description
### Describe the bug
When using the `aws-xray-sdk-core` package (possibly others as well) in a Lambda with the NodejsFunction using the now default `@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages` flag set to `true` it will fail to execute as the `@smithy/service-error-classification` will not be bundled and seems absent from the default packages installed in the runtime.
### Regression Issue
- [ ] Select this option if this issue appears to be a regression.
### Last Known Working CDK Version
The version before https://github.com/aws/aws-cdk/pull/31639 was merged and `"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true` was not the default.
### Expected Behavior
The bundled JS should work on the NodeJS 22 runtime.
Possible solutions:
- Use more granular `--external` options for the constructs bundling capabilities so the missing packages will get bundled instead of the complete exclusion of `@smithy/` at https://github.com/aws/aws-cdk/blob/ecbe1bf8e7e43d7423abfe93aa1c09189bf418c0/packages/aws-cdk-lib/aws-lambda-nodejs/lib/bundling.ts#L137
- Add the missing `@smithy/*` libraries like `@smithy/service-error-classification` (and possibly others) to the lambda environments bundled packages.
### Current Behavior
All `@smithy/*` packages are externalized by esbuild even though some might not be present in the lambda environment.
### Reproduction Steps
1. npx cdk init app --language typescript
2. Notice: `"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true` in the `cdk.json`
3. npm i esbuild @types/aws-lambda @smithy/service-error-classification
Stack:
```js
import * as cdk from 'aws-cdk-lib';
import { Duration } from 'aws-cdk-lib';
import { Architecture, Runtime } from 'aws-cdk-lib/aws-lambda';
import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
import { Construct } from 'constructs';
export class Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const fn = new NodejsFunction(this, 'Lambda', {
entry: `${__dirname}/handler.ts`,
runtime: Runtime.NODEJS_22_X,
architecture: Architecture.X86_64,
timeout: Duration.seconds(30),
bundling: {
minify: false,
format: OutputFormat.ESM,
mainFields: ['module', 'main'],
//nodeModules: ['@smithy/service-error-classification'], // If not included, results in Runtime.ImportModuleError.
banner: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);", // https://github.com/evanw/esbuild/pull/2067
target: 'node22',
},
});
}
}
```
handler.ts
```
import { isClockSkewError } from '@smithy/service-error-classification';
import { Handler } from 'aws-lambda';
export const handler: Handler = async (event, context) => {
console.log('EVENT: \n' + JSON.stringify(event, null, 2));
return isClockSkewError(new Error(''));
};
```
This will result in the following asset bundle for the lambda code:
```js
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
// lib/handler.ts
import { isClockSkewError } from "@smithy/service-error-classification";
var handler = async (event, context) => {
console.log("EVENT: \n" + JSON.stringify(event, null, 2));
return isClockSkewError(new Error(""));
};
export {
handler
};
```
And when executed will result in:
```
{
"errorType": "Error",
"errorMessage": "Cannot find package '@smithy/service-error-classification' imported from /var/task/index.mjs",
"trace": [
"Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@smithy/service-error-classification' imported from /var/task/index.mjs",
" at packageResolve (node:internal/modules/esm/resolve:844:9)",
" at moduleResolve (node:internal/modules/esm/resolve:913:18)",
" at moduleResolveWithNodePath (node:internal/modules/esm/resolve:1043:14)",
" at defaultResolve (node:internal/modules/esm/resolve:1086:79)",
" at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:650:12)",
" at #cachedDefaultResolve (node:internal/modules/esm/loader:599:25)",
" at ModuleLoader.resolve (node:internal/modules/esm/loader:582:38)",
" at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:241:38)",
" at ModuleJob._link (node:internal/modules/esm/module_job:132:49)"
]
}
```
### Possible Solution
As a workaround you can add the module problematic smithy modules to the `nodeModules` option of the `NodejsFunction` bundling options to ship them in the `node_modules` folder.
### Additional Information/Context
_No response_
### CDK CLI Version
2.176.0
### Framework Version
_No response_
### Node.js Version
22_X
### OS
macOS 15.2
### Language
TypeScript
### Language Version
_No response_
### Other information
See https://dev.classmethod.jp/articles/fix-cdk-nodejs-functions-bundle-error/ for more analysis
Contributor guide
Research direction
Start with packages/aws-cdk-lib/aws-lambda-nodejs/lib/bundling.ts around line 137, then reproduce the Node.js 22 Lambda failure using the TypeScript handler and bundling settings shown in the issue. Compare the externalized @smithy packages with those available in the Lambda environment. Done means the reproduced bundled function executes successfully without requiring a manual nodeModules workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, node.js, typescript
- Domain
- build-system, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100