13

I am using aws Step Functions to manage a workflow. I am using Fail states to handle errors within the workflow. I would like to propagate some of the json from the Step Function workflow so that a user can easily identify the source of their error. So for example, if the json input to a Fail state looked like this:

{
    "error": "some error text",
    "other_stuff": {...}
}

Then I would like to pull the source of the error. I have set up my Fail state like so:

FailState:
    Type: Fail
    Cause: States.Format($.error)
    Error: Failure Here

However, this simply produces the literal string States.Format($.error) as the Cause for the Fail state. How can I use aws states language and the Fail state to show the actual error as a part of the output of the Fail state? Any solution that can successfully propagate the error text from Step Input to Step Output for the Fail state would be sufficient to solve this problem.

5 Answers 5

13

If anyone else stumbles on this question, I contacted AWS support and this is what they told me:

"The ‘Cause’ and ‘Error’ fields in this state only accept the string type values. This is why you are getting the literal string as a response. However, the good news is that, we already have an existing feature request, pending with Step Functions Development team, to implement a feature for sending JSON Path(like $.error) into the Fail state."

So for some reason AWS step functions does not allow you to pass dynamic error messages. They did offer some workarounds such as changing the failure state to success and propagating the error message that way, or creating an sns topic in the case of statemachine failure to post to. I personally just updated the status polling API to grab the state at index [-2] to propagate the error to the user. In any case, to use this functionality currently some workaround should be employed, and hopefully AWS can get this feature out quickly.

Sign up to request clarification or add additional context in comments.

8 Comments

This feature obviously has not made it to production yet, as of today
Yes Paul, making that point especially obvious was the aforementioned pending feature request with the dev team.
Well, almost 2 years later, still didn't made into production yet :(
Checking in in 2023... my errors are still vague and unhelpful due to the lack of dynamic error messages in Fail states
This is now possible with the ErrorPath and CausePath fields stackoverflow.com/a/77106711/13191320
|
7

The latest update to Step Functions (September 2023) has this feature.

You can use JsonPath or Intrinsic Functions to create the Error and Cause dynamically:

"Fail": {
  "Type": "Fail",
  "Comment": "my error comment",
  "ErrorPath": "$.Error",
  "CausePath": "States.Format('this is the error: {}, and this is the cause: {}', $.Error, $.Cause)"
}

Full documentation here: https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-fail-state.html

Comments

3

I too want to use a JSON path in a Fail state to dynamically set the Cause and Error fields. In my case, I have a known set of errors so for each one I created a separate Fail state. Each one of those fail states corresponded with a catch object where Next is set to the appropriate fail state.

{
  "TaskState": {
    "Type": "Task",
    ...
    "Catch": [
      {
         "ErrorEquals": ["ErrorA"],
         "Next": "FailureA"
      },
      {
         "ErrorEquals": ["ErrorB"],
         "Next": "FailureB"
      }
    ]
  },
  "FailureA": {
    "Type": "Fail",
    "Error": "FailureA",
    "Cause": "This failed because of A"
  },
  "FailureB": {
    "Type": "Fail",
    "Error": "FailureB",
    "Cause": "This failed because of B"
  }
}

1 Comment

This technically works, but is not actually "dynamic", you are basically just binning errors which can't be as flexible as dynamic string formatting
2

I was able to achieve something close to a desired behavior by creating a "Fail-Me" Lambda that fails with an unhandled exception, dynamically choosing exception class based on the Error and Cause provided as its payload. If "Error" was a name of a built-in exception class it uses it, otherwise it creates its own class.

In State Machine, use an Invoke Lambda state calling this "Fail-Me" lambda with no retrier and no catcher.

import inspect, sys

# Expected payload (event), example:
#      {
#           "Error":"RuntimeError",
#           "Cause":"No Cause"
#       }

def lambda_handler(event, context):
    
    ErrorType  = event.get("Error") or ""
    ErrorCause = event.get("Cause") or ""


    if not ErrorType.isidentifier():
        ErrorCause = "{}: {}".format(ErrorType, ErrorCause)
        ErrorType = "OtherError"

    DynamicExceptionClass = type(ErrorType, (BaseException,), {})

    for name, obj in inspect.getmembers(sys.modules["builtins"]):
        if inspect.isclass(obj) and issubclass (obj, BaseException):
            if name==ErrorType:              #ErrorType is an existing built-in exception - use it
                raise obj(ErrorCause)


    #Create our own dynamic class and raise it

    DynamicExceptionClass = type(ErrorType, (BaseException,), {})

    raise DynamicExceptionClass(ErrorCause)

Comments

1

This has been added with the latest update for step functions.

Enhanced Error Handling AWS Step Functions

Example with CDK:

new Fail(this, "Failed Step", {
  cause: JsonPath.stringAt("$.payload.Cause"),
  error: JsonPath.stringAt("$.customErrorLocation"),
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.