The Lambda function returned an invalid request or response to CloudFront

lordbyron picture lordbyron · Aug 16, 2017 · Viewed 9.9k times · Source

I am attempting to follow the instructions here https://medium.com/@tom.cook/edge-lambda-cloudfront-custom-headers-3d134a2c18a2

I have CloudFront successfully sitting in front of a static S3 "hello world" HTML file, and I want to set additional headers using lambda edge, but I get an error. The really frustrating bit is that I cannot find any logs of the error to debug what is going wrong. Here is what the browser shows.

ERROR

The request could not be satisfied.

The Lambda function returned an invalid request or response to CloudFront. 
Generated by cloudfront (CloudFront)
Request ID: 2Cqex7euzH0Iigps58i9tMVxdqAaLznL2ZjwqR1sW1AZHz6x2EwfMA==

Here is the code for my simple lambda:

exports.handler = (event, context, callback) => {
    console.log(event)
    callback(null, 'Hello from Lambda');
};

The trigger type is viewer-response and is attached to my CloudFront distribution (with Cache Behavior: *, if that matters). The lambda has a role corresponding to AWSLambdaBasicExecutionRole, which gives write access to Cloudwatch.

As soon as I enable the trigger, the response to a web request changes from my "Hello world" HTML to the error above, so I know it is triggering the lambda. But in the lambda dashboard, it shows no invocations or errors. No logs appear in Cloudwatch. The CloudFront dashboard shows errors (5xx), but nothing from lambda.

If I then test my function within the lambda console by clicking to the deployed function, configuring the test event as "CloudFront Modify Response Header," and hitting Test, it is successful. And Cloudwatch shows logs and console output for the test! But still nothing in logs for the live invocation.

My only theory is something wrong with the permissions, that CloudFront cannot actually invoke the lambda (explains why there is nothing in the lambda dashboard). The last thing is that the CloudFront logs (in S3) show the web request with the 502 error and LambdaValidationError, but I cannot figure out if that helps.

Answer

Michael - sqlbot picture Michael - sqlbot · Aug 16, 2017

The example in the blog post you're looking at was valid while Lambda@Edge was still in preview (limited access to specific customers, before the launch to general availability), but it is no longer correct. Shortly before the service launched, the data structures were changed.

The response header data structures formerly looked like this:

headers['Strict-Transport-Security'] = "max-age=31536000; includeSubdomains; preload";
headers['Content-Security-Policy']   = "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'";
headers['X-Content-Type-Options']    = "nosniff";

The new structures look like this:

headers['strict-transport-security'] = [{
    key:   'Strict-Transport-Security', 
    value: "max-age=31536000; includeSubdomains; preload"
}];

headers['content-security-policy'] = [{
    key:   'Content-Security-Policy', 
    value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"
}];

headers['x-content-type-options'] = [{
    key:   'X-Content-Type-Options',
    value: "nosniff"
}];

The keys in the outer object must be the lowercase equivalent of the key value in each member of the inner objects. This change to the data structures was most likely needed in order to more accurately reflect the way HTTP headers have to be processed, since in HTTP/1.x they are not case sensitive, yet in a Javascript object, the keys are case sensitive.

If the structure returned by your code does not conform to what CloudFront requires Lambda@Edge to return, the error you see will indeed be thrown. There are no logs generated, because there is no place for the logs to go -- this error occurs outside of Lambda, on the CloudFront side of the interface boundary between Lambda and CloudFront, which doesn't generate any user-accessible logs.

See the documentation for the Response Event Structure.