How do I return errors on an AWS Lambda function written in Node.js through the AWS API Gateway using the Serverless framework?

15,314

AWS error callbacks for Node.js do not work as advertised. According to the docs, all one needs to do is ensure custom errors extend the Error prototype. However, after over 10 hours of testing, I've found this is completely untrue.

The only way to return an error callback that will return anything other than {"message": "Internal server error"} (i.e. if you have your Lambda function triggered from the API gateway) is to callback the error as though it were a success.

TL;DR: callback(errorResponse, null) does not work, but callback(null, errorResponse) does.

Share:
15,314
bfissa
Author by

bfissa

Updated on June 25, 2022

Comments

  • bfissa
    bfissa almost 2 years

    I'm writing an API for internal use, and for the first time I'm using the serverless framework. I'm writing a Lambda function in Node.js, and using the AWS API Gateway to connect to it.

    In some cases I want to return a custom error message, and I'm trying to write a function that would allow me to do that. Right now, any time the Lambda process fails, I get a standard message from the API. In the code, if I try to kill the process using process.exit(1), I get a generic error, even if I've already returned an error using callback():

    {
        "message": "Internal server error"
    }
    

    If I don't use process.exit(1), I see the error I returned via callback() in the logs, but the process continues, ultimately timing out:

    {
        "message": "Endpoint request timed out"
    }
    

    I've tried a few different ways of returning an error using the callback() method, but so far I haven't been successful. I've tried this method:

    async function return_error(callback, context, error, returnCode){
      console.error("FATAL ERROR: ", error);
      let ErrorObj = {
        errorType : "InternalServerError",
        httpStatus : 500,
        requestId : context.awsRequestId,
        errorMessage : error
    }
      callback(JSON.stringify(ErrorObj));
      process.exit(1);
    }
    

    and this one:

    async function return_error(callback, error, returnCode){
      console.error("FATAL ERROR: ", error);
      callback({
        isBase64Encoded: false,
        statusCode: returnCode,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({"Error Message:": error})
      }, null);
      process.exit(1);
    }
    

    (Sorry about the minor syntax changes between the two.)

    So far, I haven't been able to return any error to the user via the API. My error always get's logged, and the function continues. Any help would be appreciated. Thank you!

    For reference, the relevant parts of my serverless.yml file:

    service: #Name of service
    
    
    provider:
      name: aws
      runtime: nodejs8.10
      role: #ARN of Iam role
    
    functions:
      screenshot:
        handler: #Name of handler
        timeout: 30
        memorySize: 1280
        reservedConcurrency: 10
        events:
          - http: 
              method: get
              path: #path
              contentHandling: CONVERT_TO_BINARY
              authorizer:
                type: aws_iam
    
    plugins:
      - serverless-plugin-chrome
      - serverless-apigw-binary
      - serverless-apigwy-binary
    package:
      exclude:
        - node_modules/puppeteer/.local-chromium/** 
    
    custom:
      apigwBinary:
        types:
          - '*/*'
    
  • bfissa
    bfissa over 5 years
    No luck, I'm having the same problem. Just to make sure it wasn't related to the function, I hardcoded a test "error" callback in the main method, but I'm having the same results. It's weird because I'm using callback to return the results, and that works fine.
  • bfissa
    bfissa about 5 years
    It's been some time since I worked on this project, but that mirrors my experience as well. Thanks!
  • Harrison Cramer
    Harrison Cramer over 3 years
    Thank you, this seems to be true. However, this eliminates instances in your Lambda environment where you could log and track errors. How can you get around this?