Skip to content

[4.x] Fail fast when a package exceeds the AWS Lambda size limit - #459

Draft
mnapoli wants to merge 1 commit into
4.xfrom
package-size-check-4x
Draft

mnapoli wants to merge 1 commit into
4.xfrom
package-size-check-4x

Conversation

@mnapoli

@mnapoli mnapoli commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

AWS Lambda rejects deployment packages larger than 250 MB once unzipped. Today osls zips and uploads such a package anyway, and osls deploy only fails when CloudFormation creates the function, several minutes later, with a raw AWS error:

CREATE_FAILED: WebLambdaFunction (AWS::Lambda::Function)
Resource handler returned message: "Unzipped size must be smaller than 262144000 bytes (Service: Lambda, Status Code: 400, ...)"

The error doesn't say what is large or how to fix it, and a failed first deployment also leaves a rolled back stack behind.

This PR adds up the size of the files right before zipping them (the stats were already collected) and fails immediately when the package reaches the limit:

Error:
The "my-service.zip" package is 305.0 MB unzipped, above the 250 MB AWS Lambda limit (function code and layers combined).
Largest files and directories in the package:
  vendor/         273.0 MB
  node_modules/    30.0 MB
  public/           2.0 MB
  index.php         0.0 MB
Exclude files that are not needed at runtime with "package.patterns": https://github.com/oss-serverless/osls/blob/4.x/docs/guides/packaging.md#patterns
  • The check runs for service, function (individually) and layer packages, during both osls package and osls deploy, before any AWS call, and nothing is zipped.
  • The first line of the message is self-contained, because tools that wrap osls often keep only the first line of the error.
  • Sizes use 1,024-based MB, like the Lambda documentation and error messages (250 MB = 262144000 bytes).
  • The check is skipped when a plugin overrides getFileContent() or getFileContentAndStat(), because the zipped content can then differ from the files on disk.
  • Layers also count toward the limit, but the unzipped size of layers referenced by ARN is not known locally, so only packages that are too large on their own are rejected. Such a package can never be deployed as a zip.
  • The opt-in large zip memory smoke test used a 512 MiB file. It now uses a 240 MiB file, which is still well above its 128 MiB memory cap.
  • Adds a "Size limit" section to the packaging guide.

What about the 50 MB zipped limit? It only applies to code uploaded directly through the Lambda API. osls deploy uploads artifacts to S3 and CloudFormation references them, so only the 250 MB unzipped limit applies. (osls deploy function does upload the zip directly with UpdateFunctionCode, so it is still subject to the 50 MB limit. This PR doesn't change that.)

Testing

  • New unit test: sparse files (only their size is read) add up to 260 MB, zipFiles() rejects with PACKAGE_TOO_LARGE and the exact message, and no artifact is left behind.
  • Tried it on a real service with 305 MB of random files: osls package and osls deploy fail in under a second with the message above. The same service packages normally once package.patterns excludes enough files (185 MB left). A function packaged individually and a layer above the limit are rejected too.
  • npm test passes (except 2 Python invoke local tests that also fail without this change on my machine), npm run integration-test-run-package passes, the large zip smoke test passes, and prettier and eslint are clean.

Backport of #<4.x PR> to 3.x: same change, with the docs link pointing to the 3.x packaging guide.

Tested the same way. npm test passes (3511 tests, the only failure is an uncaught getRandomValues error on Node 26 that also happens without this change). The packaging integration tests and the large zip smoke test pass. On the real 305 MB service, serverless deploy fails in under a second with the new message, and a normal-size service still packages.

AWS Lambda rejects deployment packages larger than 250 MB once unzipped.
osls zipped and uploaded such packages anyway, and the deployment only
failed minutes later, when CloudFormation created the function:
"Unzipped size must be smaller than 262144000 bytes".

Add up the size of the files before zipping them and fail right away,
listing the largest top-level files and directories of the package and
pointing to `package.patterns`. This applies to service, function and
layer packages, for both `package` and `deploy`.

The check is skipped when a plugin overrides getFileContent() or
getFileContentAndStat(), as the zipped content can then differ from the
files on disk. Layers also count toward the limit, but the unzipped size
of external layers is not known locally: only packages that are too
large on their own are rejected.

Claude-Session: https://claude.ai/code/session_01Awk33iZ9mDSg1xgSAPkgGK
@GrahamCampbell

Copy link
Copy Markdown
Contributor

Is this MiB or MB. AWS Regularly typo this in their docs and write MB when they actually mean MiB. In the code you write MB but the calculations use MiB.

@GrahamCampbell

Copy link
Copy Markdown
Contributor

262144000 bytes looks like 250MiB to me, not 250MB.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants