AWS Lambda@Edge Viewer Request fails with 'The body is not a string, is not an object, or exceeds the maximum size'

Viewed 1662

I am trying to create a Lambda@Edge function to return Open Graph HTML for my Angular SPA application. I've installed it into the CloudFrond "Viewer Request" lifecycle. This lambda checks the user agent, and if it's the Facebook or Twitter crawler, it returns HTML (currently hard coded in the lambda for testing). If the request is from any other user-agent, the request is passed through to the origin. The pass-through logic is working properly, but if I try to intercept and return the Open Graph HTML for the crawlers, I get an error.

In CloudWatch, the error reported by CloudFront is:

ERROR Validation error: The Lambda function returned an invalid body, body should be of object type.

In Postman (by faking the user-agent), I get a 502 with:

The Lambda function result failed validation: The body is not a string, is not an object, or exceeds the maximum size.

I'm pulling my hair out with this one. Any ideas? Here's my lambda.

'use strict';
 
function buildReleaseResponse( request ) {
     
    const content = `<\!DOCTYPE html>
        <html lang="en">
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                <meta name="viewport" content="width=device-width, initial-scale=1" />
               
                <meta property="og:type" content="website" />
                <meta property="og:title" content="Hello, World" />
                <meta property="og:description" content="This is an Open Graph test" />
                <meta property="og:image" content="https://cdn.website.com/photos/SGmzAlNmwOGpnMeijMoW9.jpg" />
                <meta property="og:url" content="https://www.website.com/hello-world" />
               
                <title>Hello, World</title>
            </head>
            <body>
                <h1>Open Graph Test</h1>
            </body>
        </html>`;
   
    return {
        statusCode: 200,
        statusDescription: 'OK',
        headers: {
            "content-type": [
                {
                    "key": "Content-Type",
                    "value": "text/html; charset=utf-8"
                }
            ]
        },
        body: content.toString()
    };
   
}
 

exports.handler = ( event, context, callback ) => {
    const { request, response } = event.Records[0].cf;
                                           
    let userAgentStr = "";
       
    if (request.headers['user-agent']) {
      if (request.headers['user-agent'].length > 0) {
          userAgentStr = request.headers['user-agent'][0].value;
      }
    }
   
    let newResponse = null;
   
    if ( userAgentStr.match(/facebookexternalhit|twitterbot/i) ) {
        if ( request.uri.startsWith("/radio/release/") ) {
            newResponse = buildReleaseResponse(request);
        }
    }
   
    if ( newResponse === null ) {
        console.log("Passthrough.");
        callback(null, request);
    }
    else {
        console.log("Overriding response with: " + JSON.stringify(newResponse));
        callback(null, newResponse);
    }   
};

Here is the response shown in cloudwatch (conole.log)

{
    "statusCode": 200,
    "statusDescription": "OK",
    "headers": {
        "content-type": [{
            "key": "Content-Type",
            "value": "text/html; charset=utf-8"
        }],
        "cache-control": [{
            "key": "Cache-Control",
            "value": "max-age=100"
        }]
    },
    "body": "<!DOCTYPE html>\n            <html lang=\"en\">\n                <head>\n                    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n                    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n                    \n                    <meta property=\"og:type\" content=\"website\" />\n                    <meta property=\"og:title\" content=\"Yo Dog\" />\n                    <meta property=\"og:description\" content=\"Song by Raf Fiol and Mike Patterson\" />\n                    <meta property=\"og:image\" content=\"https://cdn.kompoz.com/photos/SGmzAlNmwOGpnMeijMoW9.jpeg\" />\n                    <meta property=\"og:url\" content=\"https://3-www.kompoz.com/radio/release/yo_dog\" />\n                    \n                    <title>Kompoz.com</title>\n                </head>\n                <body>\n                    <h1>Yo Dog</h1>\n                </body>\n            </html>"
}

Here is the CloudFront Lambda configuration

CloudFront Lambda configuration

1 Answers

SOLVED! I'm embarrassed to report that this issue is caused by a typo on my part. In my response object, I had:

"statusCode": 200,

But it should have been:

"status": 200,

Happy to report that it is now working. Having said that, I wish that the AWS error message was better. The message "The body is not a string, is not an object, or exceeds the maximum size" really threw me off.

Related