Repository: localstack/localstack

Issue:
 custom error return to catch from step functions
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

A lambda from my step function can return an error (if a condition is not satisfied) but in a local environment the return error does not fall in my custom catch, falling only in States.ALL.

```json
"Catch": [
        {
          "ErrorEquals": [
            "TooManyRequestsException"
          ],
          "Next": "Wait and Try Later"
        },
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "Catch All"
        }
      ]
    },
    "Wait and Try Later": {
      "Type": "Wait",
      "Seconds": 10,
      "Next": "Catch lambda"
    },
    "Catch All": {
      "Type": "Fail",
      "Cause": "Unknown error!",
      "Error": "Caiu no erro geral"
    }
```


I'm generating the error customizing like this

```javascript
module.exports.handler = async function context(
  event,
  context,
  options
) {

  class CustomError extends Error {
    constructor(message){
      super(message);
      this.name = "TooManyRequestsException"
    }
  }
  const err = new CustomError('new error')
  throw err;
}
```

### Expected Behavior


I did the same procedure in the aws console and it worked perfectly falling into the custom error, only in the development environment that I couldn't and I came for help.

Does anyone know if it can be some configuration?

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

```yaml
version: '3.8'

services:
  localstack:
    image: localstack/localstack
    environment:
      - DEBUG=true
      - SERVICES=lambda,stepfunctions,iam,apigateway,s3,ses
      - DATA_DIR=/tmp/localstack/data
      - TZ=America/Fortaleza
      - LAMBDA_DOCKER_NETWORK=payment-api
      - LAMBDA_EXECUTOR=docker
    ports:
      - 4566:4566
    volumes:
      - /tmp/localstack:/tmp/localstack
      - /var/run/docker.sock:/var/run/docker.sock
      - .:/server
    depends_on:
      - mongo
```

### Environment

_No response_

### Anything else?

_No response_


Discussion:
I ended up discovering that my error is being enveloped by localstack and it turns out that only one type of error is seen, the "invocationException".

Follow the error:

```json
{
  "errorMessage": "Lambda process returned with error. Result: {\"errorType\":\"TooManyRequestsException\",\"errorMessage\":\"message error\"}. Output:\n\u001b[32mSTART RequestId: 34019ae1-9d79-19cd-7c86-d9c69c212554 Version: $LATEST\u001b[0m\n2021-09-27T22:02:12.829Z\t34019ae1-9d79-19cd-7c86-d9c69c212554\tINFO\tentrei aqui {\n  script: 'aws --endpoint http://localhost:4566/ lambda invoke --function-name context --payload fileb://lambdas-tests/context/payload.json out.json',\n  statuscode: '503'\n}\n2021-09-27T22:02:12.832Z\t34019ae1-9d79-19cd-7c86-d9c69c212554\tINFO\tTooManyRequestsException: message error\n    at Runtime.context [as handler] (/var/task/index.js:20:17)\n    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)\n2021-09-27T22:02:12.833Z\t34019ae1-9d79-19cd-7c86-d9c69c212554\tERROR\tInvoke Error \t{\"errorType\":\"TooManyRequestsException\",\"errorMessage\":\"message error\",\"name\":\"TooManyRequestsException\",\"stack\":[\"TooManyRequestsException: message error\",\"    at Runtime.context [as handler] (/var/task/index.js:20:17)\",\"    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)\"]}\n\u001b[32mEND RequestId: 34019ae1-9d79-19cd-7c86-d9c69c212554\u001b[0m\n\u001b[32mREPORT RequestId: 34019ae1-9d79-19cd-7c86-d9c69c212554\tInit Duration: 222.67 ms\tDuration: 13.91 ms\tBilled Duration: 100 ms\tMemory Size: 1536 MB\tMax Memory Used: 41 MB\t\u001b[0m",
  "errorType": "InvocationException",
  "stackTrace": [
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_api.py\", line 753, in run_lambda\n    lock_discriminator=lock_discriminator,\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 257, in execute\n    return do_execute()\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 247, in do_execute\n    return _run(func_arn=func_arn)\n",
    "  File \"/opt/code/localstack/localstack/utils/cloudwatch/cloudwatch_util.py\", line 157, in wrapped\n    raise e\n",
    "  File \"/opt/code/localstack/localstack/utils/cloudwatch/cloudwatch_util.py\", line 153, in wrapped\n    result = func(*args, **kwargs)\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 234, in _run\n    raise e\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 220, in _run\n    result = self._execute(func_arn, func_details, event, context, version)\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 450, in _execute\n    event=stdin, env_vars=environment, func_details=func_details, docker_flags=docker_flags\n",
    "  File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 375, in run_lambda_executor\n    ) from error\n"
  ]
}
```

The type of error I want to catch in my errorEquals in the step function is inside the error message
I believe I'm encountering this bug, too. I have a state machine with `retry` and `catch` blocks I'd like to test in my Localstack environment. The state machine definition is configured to catch certain errors (e.g. `Foo.BarError`), however the observed behaviour in Localstack is that an `InvocationException` is thrown as above.

In my testing in a real AWS account, the configuration appears to work as intended (the error is caught and another branch of the state machine is entered).

Resolving patch:
diff --git a/localstack/services/awslambda/lambda_api.py b/localstack/services/awslambda/lambda_api.py
--- a/localstack/services/awslambda/lambda_api.py
+++ b/localstack/services/awslambda/lambda_api.py
@@ -807,13 +807,14 @@ def run_lambda(
 
     except Exception as e:
         exc_type, exc_value, exc_traceback = sys.exc_info()
-        # TODO: wrong mapping
         response = {
             "errorType": str(exc_type.__name__),
             "errorMessage": str(e),
             "stackTrace": traceback.format_tb(exc_traceback),
         }
         LOG.info("Error executing Lambda function %s: %s %s", func_arn, e, traceback.format_exc())
+        if isinstance(e, lambda_executors.InvocationException):
+            response = json.loads(e.result)
         log_output = e.log_output if isinstance(e, lambda_executors.InvocationException) else ""
         return InvocationResult(Response(json.dumps(response), status=500), log_output)
     finally:
diff --git a/localstack/services/awslambda/lambda_executors.py b/localstack/services/awslambda/lambda_executors.py
--- a/localstack/services/awslambda/lambda_executors.py
+++ b/localstack/services/awslambda/lambda_executors.py
@@ -1422,7 +1422,14 @@ def do_execute():
                 error,
                 "".join(traceback.format_tb(error.__traceback__)),
             )
-            raise InvocationException(result, log_output)
+            result = json.dumps(
+                {
+                    "errorType": error.__class__.__name__,
+                    "errorMessage": error.args[0],
+                    "stackTrace": traceback.format_tb(error.__traceback__),
+                }
+            )
+            raise InvocationException(result, log_output=log_output, result=result)
 
         # construct final invocation result
         invocation_result = InvocationResult(result, log_output=log_output)


Test patch:
diff --git a/tests/integration/test_stepfunctions.py b/tests/integration/test_stepfunctions.py
--- a/tests/integration/test_stepfunctions.py
+++ b/tests/integration/test_stepfunctions.py
@@ -86,7 +86,7 @@
             "Catch": [
                 {
                     "ErrorEquals": [
-                        "InvocationException",
+                        "Exception",
                         "Lambda.Unknown",
                         "ValueError",
                     ],