Search code examples
node.jsaws-lambdaaws-step-functions

How to pass additional data to the Catch task when Lambda Invoke fails with Error?


I have this lambda function written in nodejs:

exports.handler = async (event) => {
    throw new CustomError('Custom error with data!', {
        propA: 'A',
        propB: 'B',
    });
};

class CustomError extends Error {
    constructor(message, data) {
        super(message);
        this.name = this.constructor.name;
        this.data = data; // I have declared a new field which contains some useful data for handling error in other lambda function.
    }
}

I've made a state machine with this lambda function as a first task and added a catcher function for this task. When I launched a new execution, I saw the following output from the Lambda Invoke task (input to the Catch task was the same):

{
  "Error": "CustomError",
  "Cause": "{\"errorType\":\"CustomError\",\"errorMessage\":\"Custom error with data!\",\"trace\":[\"CustomError: Cannot list objects\",\"    at Runtime.exports.handler (/var/task/index.js:5:11)\",\"    at Runtime.handleOnceNonStreaming (/var/runtime/Runtime.js:74:25)\"]}"
}

As you can see, there is no data field in the Catch input. I would like to pass data object of the CustomError to the Catch task. Is this possible? Are there any other ways how to pass additional error data to the Catch task? Appreciate any help.

State machine JSON:

{
  "StartAt": "SomeJob",
  "States": {
    "SomeJob": {
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "HandleErrorTask"
        }
      ],
      "End": true,
      "Type": "Task",
      "OutputPath": "$.Payload",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "...",
        "Payload.$": "$"
      }
    },
    "HandleErrorTask": {
      "End": true,
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "...",
        "Payload.$": "$"
      }
    }
  },
  "TimeoutSeconds": 300
}

Solution

  • Given the way AWS Lambda handles Function Errors in node.js, I believe the only way you can return custom data in this scenario is in the type and message for your node.js Error. AWS Step Functions interacts with Lambda using the Invoke API Action, so there's nothing special happening or possible with Step Functions.

    That said, I can think of a couple things which might help.

    First, if the data you need in your HandleErorrTask is available in the input to the SomeJob task, you can use the ResultPath property in your Catcher. I've included an updated example below and you can read more about fallback states in the docs here. In this case, the HandleErrorTask will receive the input that SomeJob received augmented with the error information.

    {
      "StartAt": "SomeJob",
      "States": {
        "SomeJob": {
          "Catch": [
            {
              "ErrorEquals": [
                "States.ALL"
              ],
              "Next": "HandleErrorTask",
              "ResultsPath": "$.errordata"
            }
          ],
          "End": true,
          "Type": "Task",
          "OutputPath": "$.Payload",
          "Resource": "arn:aws:states:::lambda:invoke",
          "Parameters": {
            "FunctionName": "...",
            "Payload.$": "$"
          }
        },
        "HandleErrorTask": {
          "End": true,
          "Type": "Task",
          "Resource": "arn:aws:states:::lambda:invoke",
          "Parameters": {
            "FunctionName": "...",
            "Payload.$": "$"
          }
        }
      },
      "TimeoutSeconds": 300
    }
    

    Another option if you need to return specific data that is only available or generated in your function would be to not raise this as an error in your code. Instead, have your Lambda Function return successfully but with a field to indicate the logical failure that you could then use a Choice State to direct exceptional responses to your HandleErrorTask state.