AWS lambda api gateway error "Malformed Lambda proxy response"

65,081

Solution 1

Usually, when you see Malformed Lambda proxy response, it means your response from your Lambda function doesn't match the format API Gateway is expecting, like this

{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "..."
}

If you are not using Lambda proxy integration, you can login to API Gateway console and uncheck the Lambda proxy integration checkbox.

Also, if you are seeing intermittent Malformed Lambda proxy response, it might mean the request to your Lambda function has been throttled by Lambda, and you need to request a concurrent execution limit increase on the Lambda function.

Solution 2

If lambda is used as a proxy then the response format should be

{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}

Note : The body should be stringified

Solution 3

Yeah so I think this is because you're not actually returning a proper http response there which is why you're getting the error.

personally I use a set of functions like so:

    module.exports = {
        success: (result) => {
            return {
                statusCode: 200,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify(result),
            }
        },
        internalServerError: (msg) => {
            return {
                statusCode: 500,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify({
                    statusCode: 500,
                    error: 'Internal Server Error',
                    internalError: JSON.stringify(msg),
                }),
            }
        }
} // add more responses here.

Then you simply do:

var responder = require('responder')

// some code

callback(null, responder.success({ message: 'hello world'}))

Solution 4

For Python3:

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps({
            'success': True
        }),
        "isBase64Encoded": False
    }

Note the body isn't required to be set, it can just be empty:

        'body': ''

Solution 5

I had this issue, which originated from an invalid handler code which looks completely fine:

exports.handler = (event, context) => {
    return {
       isBase64Encoded: false,
       body: JSON.stringify({ foo: "bar" }),
       headers: {
          'Access-Control-Allow-Origin': '*',
       },
       statusCode: 200,
    };
}

I got the hint from examining the somewhat confusing API Gateway response logs:

> Endpoint response body before transformations: null

The way to fix it would be to either

  • Add the async keyword (async function implicitly returns a Promise):
exports.handler = async (event, context) => {
    return {
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    };
}
  • Return a Promise:
exports.handler = (event, context) => {
    return new Promise((resolve) => resolve({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    }));
}
  • Use the callback:
exports.handler = (event, context, callback) => {
    callback({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    });
}

My handler was previously declared async without ever using await, so I removed the async keyword to reduce complexity of the code, without realizing that Lambda expects either using async/await/Promise or callback return method.

Share:
65,081

Related videos on Youtube

jjbskir
Author by

jjbskir

The best way through it is through it.

Updated on April 30, 2022

Comments

  • jjbskir
    jjbskir almost 2 years

    I am trying to set up a hello world example with AWS lambda and serving it through api gateway. I clicked the "Create a Lambda Function", which set up the api gatway and selected the Blank Function option. I added the lambda function found on AWS gateway getting started guide:

    exports.handler = function(event, context, callback) {
      callback(null, {"Hello":"World"});  // SUCCESS with message
    };
    

    The issue is that when I make a GET request to it, it's returning back a 502 response { "message": "Internal server error" }. And the logs say "Execution failed due to configuration error: Malformed Lambda proxy response".

  • Neo
    Neo over 6 years
    If "response" is the name of your object, using JSON.stringify(response) does not work. Leaving it like this worked for me. callback(null,response);
  • selftaught91
    selftaught91 over 6 years
    @Neo You don't need to stringify the response object. You need to stringify the data inside the body key of response object
  • andy mccullough
    andy mccullough over 6 years
    Out of curiosity - why does the body need to be stringified? This was a my issue on something i've been working on, and its left me confused - thanks
  • Palisand
    Palisand over 6 years
  • craigmichaelmartin
    craigmichaelmartin over 6 years
    Here is an AWS support article on it: aws.amazon.com/premiumsupport/knowledge-center/…
  • Trenton
    Trenton about 6 years
    Of these, only statusCode is required for a call from API Gateway to succeed.
  • Kimutai
    Kimutai almost 5 years
    Ensuring the body is stringified worked for me. Thanks a lot +1
  • Santhosh Nagulanchi
    Santhosh Nagulanchi almost 5 years
    Now, if we use Access-Control-Allow-Credentials value as true,we cant keep 'Access-Control-Allow-Origin' value as '*'
  • Santhosh Nagulanchi
    Santhosh Nagulanchi almost 5 years
    I observed it supports only one Origin: headers: { "Access-Control-Allow-Origin" : "<<Single Domain>>", "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS },
  • Misha
    Misha about 4 years
    OMG, thank you so much, you just saved me after hours of trying to figure out how to freakin get a header in the response. I tried plain JSON, didn't work. I tried key value pairs, didn't work. Dictionary was the way to go! THANK YOU!
  • Waleed93
    Waleed93 almost 4 years
    This answer was really helpful. Thanks!
  • mgarciaisaia
    mgarciaisaia almost 4 years
    The body should be stringified OMG thanks for that
  • nog642
    nog642 almost 3 years
    What if we're using WebSockets, not HTTP?
  • Vimanyu
    Vimanyu almost 3 years
    I did the exact same thing - removed async as I removed the await and started hitting the exact same issue! Your post really helped. Thanks!