Search code examples
amazon-web-servicesaws-lambdaaws-step-functions

How to populate error from child workflow to parent workflow?


I got two step functions. Parent step function call Child step function and wait for result. It works as expected in happy scenario. But when Child step function's lambda throw error and failed. Parent step function only receive States.TaskFailed the detail error code from lambda is omitted. Is there a way to get that error out?

Here is my sample function:

{
    "Comment": "Parent state machine",
    "StartAt": "CallChildAndWait",
    "States": {
        "CallChildAndWait": {
            "Type": "Task",
            "Resource": "arn:aws:states:::states:startExecution.sync:2",
            "Parameters": {
                "Input":{
                    "Comment": "Pretent that my input goes here",
                    "AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$": "$$.Execution.Id"
                },
                "StateMachineArn.$": "arn:child-state-machine-step-fn"
            },
            "End": true
        }
    }
}

{
    "Comment": "Child state machine",
    "StartAt": "DoSomethingAndReturn",
    "States": {
        "DoSomethingAndReturn": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "Parameters":{  
                "FunctionName":"MyFunction"
            },
            "End": true
        }
    }
}

and lambda function that throw error 50% chance

class RandomError extends Error {
  name = 'RANDOM_ERROR'
  message = 'Just failed randomly'
}

export const handler = async (event) => {
  const dice = Math.round(Math.random() * 10);
  
  if (dice >= 5) {
    throw new RandomError('Crashed');
  }
  
  return {success: true}
}

How do I get RANDOM_ERROR error code from parent step function Catch handler? This is all I got from parent

{
  "Error": "States.TaskFailed",
  "Cause": "A very big json string and RANDOM_ERROR no where to be found"
}

I could also do waitForTaskToken and report success failed directly from lambda but I tried to avoid that (since have to bundle aws-sdk)


Solution

  • One solution can be catching the Lambda error in the Child state machine and building an object with all necessary information.

    For example the Child can be:

    {
      "Comment": "Child state machine",
      "StartAt": "DoSomethingAndReturn",
      "States": {
        "DoSomethingAndReturn": {
          "Type": "Task",
          "Resource": "arn:aws:states:::lambda:invoke",
          "Parameters": {
            "FunctionName": "MyFunction"
          },
          "End": true,
          "Catch": [
            {
              "ErrorEquals": [
                "States.ALL"
              ],
              "Next": "Pass",
              "ResultPath": "$.errorDetails"
            }
          ]
        },
        "Pass": {
          "Type": "Pass",
          "End": true,
          "Parameters": {
            "IsSuccessful": false,
            "Details.$": "$.errorDetails"
          }
        }
      }
    }
    

    You catch the error, add all error details to input object using "ResultPath" in Catch. Then use Pass to build the final output object.

    In the Parent then you can check IsSuccessful and make decisions based on that.