aws-amplify / aws-amplify/amplify-hosting

502 error on Amplify SSR Functions if uncompressed response size is over 1MB

Open
#2,221 2 comments 0 reactions 0 assignees View on GitHub
bug pending-investigation ssr
Dominant language
Dockerfile
Stars
481
Forks
123
PR merge metrics
No merged PRs in 30d

Description

### Before opening, please confirm:

- [X] I have checked to see if my question is addressed in the [FAQ](https://github.com/aws-amplify/amplify-console/blob/master/FAQ.md).
- [X] I have [searched for duplicate or closed issues](https://github.com/aws-amplify/amplify-console/issues?q=is%3Aissue+).
- [X] I have read the guide for [submitting bug reports](https://github.com/aws-amplify/amplify-console/blob/master/CONTRIBUTING.md).
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.

### App Id

d2icpnoec5rp5b

### Region

us-east-1

### Amplify Console feature

Not applicable

### Describe the bug

We noticed that one of our SSR API routes (defined in the /pages/api directory of our Next.js app) was 502ing in production (Amplify to Lambda@Edge,) but working as expected running locally. With a bit of research and viewing the logs, we discovered that this was because the response was over CloudFront’s 1MB limit for “Size of a response that is generated by a Lambda function, including headers and body.”

```
ERROR Validation error: The Lambda function returned an invalid response, the length of the body size and header was 1054968 bytes which exceeded the CloudFront limit of 1048576 bytes on the maximum length of the request including body size and headers.
```

This was strange though, because even though the uncompressed size was 1.01MB locally, the actual response size was around 241kb. This is according to the network inspector in the browser. This difference makes sense, Next.js uses gzip internally to compress the responses to save space. If CloudFront was receiving this 241kb response from the Lambda function, it shouldn’t be failing for being too large.

Other responses from the same route (with different parameters) were coming back from Lambda@Edge with gzip compression. It would appear that CloudFront is not accepting the gzip compressed response of the Lambda function, and is either bypassing the internal Next.js gzip, or is uncompressing the response before processing it. Then, before it is sent as a final response, it is applying its own gzip compression again.

### Expected behavior

Since the final compressed response was under 1MB, we expected this route to work without hitting the size limitation.

### Reproduction steps

1. Create an API route in a Next.js project that will deliver an uncompressed response size of **over** 1MB, but a compressed size of **under** 1MB.
2. Even though the final compressed size will be under 1MB, the CloudFront error will occur, and a log message will be generated saying the response was too large.

In our case, we are processing a large number of Salesforce records and returning the result as JSON. The uncompressed response was 1.01MB but compressed it was 241KB. This caused the error, even though 241KB is well within the 1MB limit.

### Build Settings

_No response_

### Additional information

# Workaround
On the problematic API route, I manually added gzip compression to the response by using the zlib library and setting the Content-Encoding header to “gzip”. Even though Next.js usually does this part on its own internally, I suspected that doing it manually would “force” CloudFront to accept the gzipped version of the response, which would be within the size limitation.

Before deploying, I tested the workaround locally and was happy to see that it worked exactly as expected. The network inspector showed the same response size and uncompressed size as before, even though now I was manually adding the gzip compression. This means that Next.js luckily didn’t “double compress” the response, which was exactly what we needed.

So it was time to deploy to Amplify. We were pleasantly surprised to find that the API route now worked perfectly! Even though the uncompressed size was still over the 1MB limit, the response being sent to CloudFront was well under the limit, and so it was processed successfully. CloudFront also must have noticed it was already compressed with gzip, so it also did not “double compress” the response. This also suggests that CloudFront wasn’t uncompressing the response from the Lambda first, because that would have happened here too.

Luckily, this is our only API route that comes close to the size limit, so we don’t need to manually re-add gzip compression to everything. That would be a pretty tedious “solution” to the issue at hand.

# Conclusion

It seems like if Lambda didn’t ignore/bypass the native gzip compression of Next.js, it could process much “larger” response payloads that are still well within the 1MB limit, provided they are compressed with Next.js internal gzip before CloudFront has to handle it.

In conclusion, the 1MB Lambda@Edge response limit in a Next.js SSR Amplify project currently effectively applies to the **uncompressed** size, even though the **actual final response size** will still be compressed with gzip and might well be under the 1MB limit. At the very least, this limitation should be clarified in the Amplify, CloudFront, or Lambda@Edge documentation.

Contributor guide

Open the contributing guide

Research direction

Start with the Next.js /pages/api route and reproduce a response over 1 MB uncompressed but under 1 MB when gzipped, then inspect the Lambda@Edge and CloudFront logs. Compare the failing response with the manual zlib and Content-Encoding: gzip workaround; done means the behavior is fixed or the effective response-size limitation is clearly documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, next.js
Domain
api, backend, cloud
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.