Step Functions States.TaskFailed and States.Timeout, Fixed: Read Error and Cause, Retry Only What Recovers, Catch With ResultPath, the TaskFailed Wildcard Trap, Redrive and Alerts
AWS Step Functions States.TaskFailed means a Task state could not complete successfully, often because an integrated AWS Lambda function threw an exception or an external service returned an error. States.Timeout means a task or execution exceeded its time limit. The quickest way to fix either failure is to open the execution history, identify the failed state, inspect its Error and Cause fields, and add a targeted Retry or Catch rule. But there is an important catch: States.TaskFailed acts as an error-matching wildcard that excludes States.Timeout. Retrying the wrong errors, or catching them without preserving the original input, can hide the actual problem and make your workflow harder to recover.
Jake owns a mobile phone repair shop with a website that accepts repair bookings. Every new booking triggers a Step Functions workflow that checks spare-parts availability, contacts a supplier API, calculates a repair estimate, and sends a confirmation to the customer.
Most bookings complete successfully. But occasionally the supplier API responds slowly or returns a temporary error. The Step Functions console shows a failed execution, and Jake sees States.TaskFailed. He assumes the entire workflow has broken and starts looking at the confirmation email Lambda.
The email function has not even started. The execution history points to the supplier-checking task, where a temporary upstream failure stopped the workflow. Jake's problem is not that Step Functions cannot orchestrate Lambda; it is that the supplier task needs a clear recovery policy.
What States.TaskFailed actually means
Your Step Functions workflow runs as a series of states. A Task state performs work through a supported resource integration, such as invoking Lambda, starting a service operation, calling an HTTP endpoint, or running another workflow.
When one of your Tasks cannot complete, Step Functions records an error. The error might originate in the integrated service, the Lambda application code, a network-related operation, or the Step Functions integration itself.
States.TaskFailed is a built-in Step Functions error name. It can represent task failure, but it also has a special meaning inside ErrorEquals: it matches known task errors except States.Timeout.
That means an application error named SupplierUnavailableError can be matched by a retrier using States.TaskFailed, but a task timeout will not match that same rule. If you need to handle timeouts, specify States.Timeout or another appropriate error name explicitly.
You also need to keep the error apart from the execution status. A workflow might contain a Task failure that is successfully caught and recovered. The overall execution can still finish with SUCCEEDED.
Jake: "Does States.TaskFailed mean my entire workflow has permanently failed?"
Ethan: "Not necessarily. It means a task failed. A retry or fallback can recover from the problem and allow the workflow to finish."
Understand TaskFailed, Timeout, Runtime, and Permissions
Your Step Functions failures will not all share one cause or one fix. The error name provides an initial classification, and the accompanying cause provides additional details.
States.Timeout indicates that a task or execution exceeded an applicable deadline. States.Permissions indicates insufficient privileges to execute a Task. States.Runtime represents a workflow-processing failure, often associated with invalid runtime data or JSONPath processing.
Retries help you with temporary problems, but they are not a universal repair. A missing IAM permission normally remains missing on the next attempt. A malformed JSONPath is unlikely to become valid just because the task runs again.
| Error | Meaning | Recommended response |
|---|---|---|
States.TaskFailed | Task operation failed; also a retry/catch wildcard | Inspect underlying error; selectively retry |
States.Timeout | Task or workflow exceeded deadline | Inspect latency, limits, and timeout settings |
States.HeartbeatTimeout | Required task heartbeat not received | Repair heartbeat logic or worker health |
States.Permissions | Task lacks necessary privileges | Fix execution-role or resource permissions |
States.Runtime | Workflow runtime processing error | Correct definition or input shape |
States.DataLimitExceeded | Payload exceeds applicable quota | Reduce payload or reference data externally |
Two errors deserve your particular caution. States.Runtime cannot be retried or caught by a normal state-level error handler. States.DataLimitExceeded is terminal and is not caught by States.ALL.
Also, keep States.Permissions apart from the access-denied errors an integrated AWS service can return. Some integrations expose a service-specific error name. Always inspect the actual error string before writing a matcher.
Find the failing state in execution history
Your execution history is the best starting point when a Standard Workflow fails. It records state transitions, scheduled tasks, task results, retries, and failures. The execution graph helps locate the state responsible for the failure.
Open the Step Functions console, select the state machine, and choose the relevant execution. The execution details page displays the status and a graph of the workflow. Select the failed state to inspect its input, output, events, and retry attempts when available.
- Open Step Functions in the AWS console.
- Select State machines and choose the workflow.
- Open the Executions tab.
- Select the failed or timed-out execution.
- Find the failed state in the execution graph.
- Inspect its Input, Output, Details, and Events.
- Open the failed event to find the error name and cause.
For a Lambda integration, the selected Task can also give you a link to the function and its CloudWatch logs. This helps connect the state-machine failure to the actual function invocation.
The history is particularly useful when several tasks perform similar operations. Rather than searching every Lambda log group, you can identify which state was running when the failure occurred and narrow the investigation to that resource.
Jake: "My workflow has six Lambda functions. How do I know which one caused the problem?"
Ethan: "Open the failed execution and select the red task. Its events identify the failed integration, and the details can lead you to the corresponding logs."
Read Error and Cause instead of guessing from the status
Step Functions failure information commonly contains two important fields: Error and Cause. The error is the machine-readable identifier used for retry and catch matching. The cause provides a human-readable description and can include serialized information from the integrated service.
Here is what a failed Lambda task can look like in your history:
{
"Error": "SupplierUnavailableError",
"Cause": "{\"errorMessage\":\"Supplier returned HTTP 503\",\"errorType\":\"SupplierUnavailableError\"}"
}
In this example, you can see the real issue: a supplier service returning HTTP 503. Retrying the operation after a delay may help. The error name can be matched explicitly as SupplierUnavailableError, rather than automatically retrying every possible failure.
The Cause value is often a string rather than an already-parsed JSON object. If it contains JSON text, your application might need to parse it before referring to nested properties. In a JSONPath-based state machine, the intrinsic States.StringToJson can convert a suitable JSON string.
Your causes will not always contain JSON. Some integrations return descriptive text. Build fallback handlers that tolerate different cause formats, and keep the raw cause away from your customers, because it may contain internal diagnostic information.
Use the AWS CLI to inspect exact execution failures
When you have the execution ARN, use describe-execution to retrieve its overall status and top-level error details. This is useful for determining whether the execution ended with FAILED, TIMED_OUT, or another status.
Next, use get-execution-history to inspect individual state transitions. The API supports pagination, and you can request the newest events first. AWS CLI pagination can be used to continue through larger histories.
aws stepfunctions describe-execution \
--execution-arn "$EXECUTION_ARN" \
--region us-east-1
aws stepfunctions get-execution-history \
--execution-arn "$EXECUTION_ARN" \
--reverse-order \
--region us-east-1
For a focused diagnostic, use a JMESPath query to return failure events and their details:
aws stepfunctions get-execution-history \
--execution-arn "$EXECUTION_ARN" \
--reverse-order \
--query "events[?contains(type, 'Failed') || contains(type, 'TimedOut')].{
Type:type,
TaskFailure:taskFailedEventDetails,
LambdaFailure:lambdaFunctionFailedEventDetails,
ExecutionFailure:executionFailedEventDetails,
TaskTimeout:taskTimedOutEventDetails
}" \
--region us-east-1
Different integration types can produce different event-detail structures. If a filtered query does not reveal the cause, retrieve the unfiltered event history and examine the relevant event. The service's event record, not a guessed property name, is the authoritative diagnostic source.
Important: GetExecutionHistory is available for Standard Workflows, not Express Workflows. To diagnose Express executions, configure the appropriate CloudWatch Logs delivery and examine the execution's logged events.
Understand how unhandled Lambda exceptions reach Step Functions
A common source of your task failures is a Lambda function that raises an exception without handling it. In a synchronous Step Functions Lambda integration, a function error causes the task to fail, with the error information exposed to Step Functions.
In Python, the exception class can determine the reported error type. For example, a custom SupplierUnavailableError exception can make it possible for the workflow to distinguish temporary supplier problems from other application failures.
class SupplierUnavailableError(Exception):
pass
def lambda_handler(event, context):
order_id = event["orderId"]
supplier_available = False
if not supplier_available:
raise SupplierUnavailableError(
f"Supplier API unavailable for order {order_id}"
)
return {
"orderId": order_id,
"supplierStatus": "AVAILABLE"
}
This Lambda intentionally raises an exception to demonstrate an unsuccessful invocation. A real implementation would inspect the supplier's HTTP response and raise a retryable exception only for temporary conditions.
Lambda error naming varies with the language runtime and failure type. Some unhandled errors can appear as runtime-specific names. Historically, Lambda.Unknown was common; newer runtimes can report timeout-related errors such as Sandbox.Timedout.
Service-side failures may produce names such as Lambda.ServiceException, Lambda.SdkClientException, or Lambda.TooManyRequestsException. These are useful candidates for selective retries because they can represent temporary service failures or throttling.
A function returning a normal JSON response with {"success":false} does not automatically fail the task. If the function returns successfully, Step Functions treats the integration as successful unless the state machine explicitly evaluates that response and chooses a failure path.
Add Retry blocks to handle temporary problems automatically
You can put retry policies on Task, Parallel and Map states. A Retry field contains one or more retriers. Each retrier defines which error names to match and how long to wait between attempts.
The essential retry fields are ErrorEquals, IntervalSeconds, MaxAttempts, and BackoffRate. Optional settings include MaxDelaySeconds and JitterStrategy.
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException",
"SupplierUnavailableError"
],
"IntervalSeconds": 2,
"MaxAttempts": 3,
"BackoffRate": 2,
"MaxDelaySeconds": 10,
"JitterStrategy": "FULL"
}
]
Here, MaxAttempts: 3 means three retries after the original failed attempt, giving up to four total attempts. Exponential backoff lengthens the delay between retries instead of immediately repeating the same request.
With an interval of two seconds and a backoff rate of two, the nominal retry delays are two, four, and eight seconds. The FULL jitter strategy randomizes the actual delays within the applicable ranges, which helps reduce synchronized retry storms when many executions fail simultaneously.
Jake: "Why not retry the supplier call ten times without waiting?"
Ethan: "If the supplier is overloaded, immediate retries add more pressure. Bounded retries with backoff give the service time to recover."
Retry only specific errors instead of every failure
Some errors are worth retrying, and some are not. A supplier returning HTTP 503 might recover after a delay, but an invalid order number will not become valid through repetition. Retrying both creates wasted work and delays meaningful feedback.
Use custom application error names to separate temporary and permanent failures. For example, your Lambda can raise SupplierUnavailableError when receiving HTTP 503 and InvalidOrderError when the order data is invalid.
Then retry only SupplierUnavailableError and service-level failures. Let InvalidOrderError proceed directly to a fallback that explains why the order could not be processed.
"Retry": [
{
"ErrorEquals": [
"SupplierUnavailableError",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 3,
"MaxAttempts": 2,
"BackoffRate": 2
}
]
Your error names are case-sensitive. SupplierUnavailableError and supplierUnavailableError are not interchangeable. Use the exact string that the failed execution reports.
A broad States.ALL retrier can help you in limited circumstances, but keep it out of your default for every Task. It can retry invalid inputs, permission errors, and other problems that require human correction.
Use Catch to route exhausted failures to a fallback state
Retries handle temporary failures. Catchers handle errors that either have no matching retry policy or remain after the applicable retries are exhausted. A Catch field defines error matchers and the next state to enter when those errors occur.
A catcher requires ErrorEquals and Next. In JSONPath-based state definitions, an optional ResultPath controls where the error information is inserted into the state input.
"Catch": [
{
"ErrorEquals": ["States.Timeout"],
"ResultPath": "$.taskError",
"Next": "TimeoutFallback"
},
{
"ErrorEquals": ["States.TaskFailed"],
"ResultPath": "$.taskError",
"Next": "GeneralFallback"
}
]
The first catcher matches task timeouts, while the second handles other task failures. Since catchers are evaluated in order, specific error handlers should generally appear before broad catchers.
A fallback can notify support, record a failed payment attempt, place the order into a manual-review queue, or provide a controlled outcome. The correct fallback depends on whether the workflow can safely continue without the failed operation.
States.ALL is a catch-all matcher with special limitations. It must appear alone in its ErrorEquals array and at the end of the catcher list. It cannot catch States.Runtime or the terminal States.DataLimitExceeded error.
Preserve original input when passing an error to the fallback
A common mistake is catching an error without thinking about how your fallback state receives its input. By default, the caught error output can replace the original state input. Your fallback may then receive the error but lose fields such as orderId, customerId, or bookingDate.
Use ResultPath in a JSONPath-based workflow to store the error under a new field. This keeps the original business data available for recovery actions.
"Catch": [
{
"ErrorEquals": ["States.ALL"],
"ResultPath": "$.errorInfo",
"Next": "ManualReview"
}
]
Suppose the original Task input was:
{
"orderId": "ORDER-1042",
"customerId": "CUSTOMER-71"
}
After a caught failure, the fallback can receive an object like this:
{
"orderId": "ORDER-1042",
"customerId": "CUSTOMER-71",
"errorInfo": {
"Error": "SupplierUnavailableError",
"Cause": "Supplier returned HTTP 503"
}
}
The fallback now knows which order failed and why. This is far more useful than receiving only the error message, particularly when your recovery process sends a customer notification or records a support ticket.
Jake: "My fallback Lambda receives the error but not the order number. Where did the order data go?"
Ethan: "Your Catch replaced the input. Add ResultPath to preserve the order and place the error inside it."
Worked example: Retry a flaky supplier API call with exponential backoff
Suppose Jake's booking workflow calls a Lambda function named CheckSupplier. The function contacts a supplier API that occasionally returns HTTP 503. Without retries, a brief supplier outage ends the booking process and leaves the customer without a confirmation.
The design goal is to retry temporary supplier problems, route exhausted errors to manual review, preserve the original order, and avoid repeatedly retrying permanent invalid-order failures.
First, the Lambda function should translate the temporary supplier response into a meaningful application exception. This illustrative Python example assumes the supplier URL is provided securely in the environment and that each request has a timeout.
import json
import os
import urllib.error
import urllib.parse
import urllib.request
class SupplierUnavailableError(Exception):
pass
class InvalidOrderError(Exception):
pass
def lambda_handler(event, context):
order_id = event.get("orderId")
if not order_id:
raise InvalidOrderError("Missing orderId")
base_url = os.environ["SUPPLIER_API_URL"]
query = urllib.parse.urlencode({"orderId": order_id})
url = f"{base_url}?{query}"
try:
with urllib.request.urlopen(url, timeout=8) as response:
return {
"orderId": order_id,
"supplier": json.loads(response.read())
}
except urllib.error.HTTPError as error:
if error.code in (429, 500, 502, 503, 504):
raise SupplierUnavailableError(
f"Supplier returned HTTP {error.code}"
) from error
raise
except (urllib.error.URLError, TimeoutError) as error:
raise SupplierUnavailableError(
"Supplier API connection failed"
) from error
Next, create a state machine that calls this Lambda synchronously. The example uses the optimized Lambda integration and JSONPath fields. Replace the sample Lambda ARN with the actual function ARN in your account and ensure that the state machine execution role is authorized to invoke it.
The complete example includes bounded retries, separate timeout handling, a fallback path, and a final failure state when manual intervention is necessary.
{
"Comment": "Supplier check with retries and fallback",
"StartAt": "CheckSupplier",
"States": {
"CheckSupplier": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "arn:aws:lambda:us-east-1:123456789012:function:CheckSupplier",
"Payload.$": "$"
},
"ResultSelector": {
"supplierResult.$": "$.Payload"
},
"ResultPath": "$.supplierCheck",
"TimeoutSeconds": 20,
"Retry": [
{
"ErrorEquals": [
"SupplierUnavailableError",
"Lambda.ServiceException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 2,
"MaxAttempts": 3,
"BackoffRate": 2,
"MaxDelaySeconds": 10,
"JitterStrategy": "FULL"
}
],
"Catch": [
{
"ErrorEquals": [
"States.Timeout",
"Sandbox.Timedout"
],
"ResultPath": "$.errorInfo",
"Next": "ManualReview"
},
{
"ErrorEquals": [
"States.TaskFailed"
],
"ResultPath": "$.errorInfo",
"Next": "ManualReview"
}
],
"Next": "BookingConfirmed"
},
"BookingConfirmed": {
"Type": "Succeed"
},
"ManualReview": {
"Type": "Pass",
"Parameters": {
"orderId.$": "$.orderId",
"error.$": "$.errorInfo"
},
"Next": "SupplierCheckFailed"
},
"SupplierCheckFailed": {
"Type": "Fail",
"Error": "SupplierCheckFailed",
"Cause": "Supplier check requires manual review"
}
}
}
This example uses a Pass state named ManualReview to preserve and reshape the error information before failing the workflow. It does not actually create a support ticket or publish a notification. In a production implementation, replace or extend that state with a Task that writes to an approved recovery destination, then decide whether the overall workflow should fail or complete in a controlled review state.
The States.TaskFailed catcher handles errors other than Step Functions task timeouts. The preceding timeout catcher explicitly handles States.Timeout and the Lambda runtime timeout identifier Sandbox.Timedout.
Also notice the distinction between Task timeout and Lambda timeout. A Lambda invocation that reaches the function's own configured timeout can return a Lambda-specific error such as Sandbox.Timedout, rather than the task-level States.Timeout identifier.
Finally, ensure the supplier operation is safe to retry. A read-only inventory lookup is usually easier to retry than creating a payment or submitting a purchase order. For operations with side effects, use an idempotency key so repeated attempts cannot accidentally create duplicate business transactions.
Calculate retry attempts and understand backoff behavior
When you configure MaxAttempts, remember that it counts retries, not the original attempt. A retrier with MaxAttempts: 3 permits the original attempt plus up to three additional attempts.
With IntervalSeconds: 2 and BackoffRate: 2, the nominal waits are two seconds, four seconds, and eight seconds. A maximum delay can cap the increasing backoff. Jitter randomizes wait durations to distribute load.
| Attempt | Nominal wait before attempt | What happens |
|---|---|---|
| Initial | 0 seconds | First supplier call |
| Retry 1 | 2 seconds | Retry temporary error |
| Retry 2 | 4 seconds | Retry if still failing |
| Retry 3 | 8 seconds | Final permitted retry |
These timings are illustrative nominal delays without jitter. With JitterStrategy: FULL, the actual waits are randomized. Task execution time and scheduling overhead also affect the total duration.
Keep overall workflow deadlines in mind. Even if a retry policy allows more attempts, the workflow or Task may reach a timeout before all planned retries finish.
For expensive external operations, smaller retry limits may be appropriate. For throttling and short-lived service exceptions, exponential backoff often provides a better balance between responsiveness and protection of the downstream service.
Fix a Catch block that never triggers
If your Task fails but the workflow does not enter the fallback state, begin by checking whether the catcher matches the actual error name. A spelling difference, unexpected integration error, or omitted timeout matcher can prevent the Catch rule from being selected.
For example, States.TaskFailed excludes States.Timeout. If your catcher only matches States.TaskFailed, a timeout can bypass it. Add a separate States.Timeout catcher when that outcome should be handled.
Another common mistake is attaching Catch to the wrong state. If the error occurs in a later Task or inside a Parallel or Map branch, a catcher on an unrelated earlier Task will not handle the failure. Catchers apply within the scope of the state where they are defined.
| Reason Catch did not run | Correction |
|---|---|
| Wrong error name | Match exact Error value |
| Only TaskFailed catches configured | Handle timeout separately |
| Catch attached to wrong state | Move catcher to failing Task or enclosing supported state |
| States.Runtime occurred | Correct runtime data or definition |
| Execution-level timeout | Use external monitoring and redesign deadline |
| Earlier catcher matched | Reorder specific and broad catchers |
| Fallback itself failed | Inspect subsequent history events |
Remember that States.ALL is not an unlimited safety net. It cannot catch runtime errors or certain terminal conditions. Also, a top-level execution timeout is not handled by a Task's Catch block as though it were an ordinary Task failure.
When a catcher does match, inspect whether the fallback state actually ran successfully. A fallback might fail because of a missing JSONPath, an unavailable service, or a permissions error, making it appear that Catch never worked.
Configure task-level and state-machine-level timeouts correctly
You have several timeout mechanisms to work with. A Task's TimeoutSeconds limits how long that task can run. A state machine's top-level TimeoutSeconds limits the overall execution duration in supported workflow types.
For callback and activity patterns, HeartbeatSeconds can require periodic heartbeat reports. If the required heartbeat does not arrive, Step Functions can fail the task with a heartbeat-related timeout. Heartbeats are not the same as extending the task's overall execution deadline.
{
"StartAt": "CallService",
"TimeoutSeconds": 300,
"States": {
"CallService": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "arn:aws:lambda:us-east-1:123456789012:function:CallService",
"Payload.$": "$"
},
"TimeoutSeconds": 30,
"End": true
}
}
}
In this example, the workflow has an overall deadline of 300 seconds, while the Task has a separate 30-second deadline. A Task-level timeout may be caught by a matching catcher on that Task. A top-level workflow timeout ends the execution and requires external handling or a redesign that avoids crossing the deadline.
The Lambda function has its own timeout configuration as well. For reliable diagnostics, understand which timeout expires first. A Lambda timeout can produce a Lambda-specific failure name, while a Step Functions timeout can produce States.Timeout.
For Standard Workflows, the maximum execution duration is much longer than for Express Workflows. Express Workflows have a maximum execution duration of five minutes. Choose the workflow type and deadlines based on the actual business process rather than trying to force long-running work through short execution limits.
Skip retries for errors that cannot recover on their own
Your retry policy should separate temporary failures from structural problems. Temporary network errors, throttling, and some service exceptions may recover. Incorrect IAM permissions, invalid state input, missing resources, and schema mistakes generally require a change outside the current task attempt.
For example, if the Step Functions execution role lacks permission to invoke Lambda, retrying the same invocation does not grant permission. Examine the execution role's IAM policy, the target resource policy when relevant, and any organizational restrictions.
A States.Runtime failure may arise when the workflow attempts to apply a JSONPath to missing or null data in an unsupported way. This is a workflow-definition or input-shape problem. It must be fixed rather than retried.
A large payload can produce States.DataLimitExceeded. Instead of making more attempts with the same oversized payload, reduce the amount of data passing between states. For large documents, store content in Amazon S3 and pass object references rather than entire payloads.
Be careful with non-idempotent API operations. A supplier API might process a request but time out before Step Functions receives the response. Retrying without an idempotency key can submit the same order twice. Recovery correctness matters as much as successful execution status.
Jake: "If a request times out, doesn't that mean the supplier definitely didn't process it?"
Ethan: "No. The supplier may have processed it but failed to respond in time. Use idempotency keys before enabling automatic retries for operations with side effects."
Recover failed executions using Step Functions redrive
A failed execution rarely means you must start the entire workflow again. Step Functions supports redriving eligible unsuccessful Standard Workflow executions. Redrive resumes the execution from the unsuccessful state while retaining completed work from earlier successful states.
Standard Workflow executions that failed, were aborted, or timed out can be eligible for redrive during a 14-day redrive period. Additional eligibility requirements apply, including execution history limits and the execution's maximum open duration.
In the console, open an eligible unsuccessful Standard execution and choose the available redrive action. The execution uses its original state machine definition and retains the same execution ARN. It does not automatically use a newly edited workflow definition.
aws stepfunctions redrive-execution \
--execution-arn "$EXECUTION_ARN" \
--region us-east-1
Redrive can reset the retry attempt counts for rerun Task, Parallel, and Inline Map states, allowing their configured retry budgets to apply during the redrive attempt. Successful preceding states are generally not rerun, although the precise behavior depends on the failed state type.
Express Workflow executions cannot be redriven through the Standard execution redrive API. Express child workflows in certain Distributed Map scenarios have a different recovery mechanism through redriving the Map Run.
If you changed the state machine definition to fix a code-path problem, remember that redrive uses the original definition. Start a new execution using the updated workflow when you need that new definition. The distinction prevents a redrive from repeatedly following logic you already know is incorrect.
Alert when Step Functions executions fail or time out
Even your best-designed workflow can hit problems that exceed its recovery budget. Configure monitoring so those failures reach an operator rather than remaining unnoticed in the execution list.
Step Functions publishes metrics in the AWS/States namespace. ExecutionsFailed records failed executions, while ExecutionsTimedOut records executions that exceeded their deadline. For count metrics, use the Sum statistic when creating alarms.
A CloudWatch alarm can notify an Amazon SNS topic when the failure count crosses a threshold. This provides operational visibility without requiring someone to continually open the Step Functions console.
aws cloudwatch put-metric-alarm \
--alarm-name "BookingWorkflowFailures" \
--namespace AWS/States \
--metric-name ExecutionsFailed \
--dimensions Name=StateMachineArn,Value="$STATE_MACHINE_ARN" \
--statistic Sum \
--period 300 \
--evaluation-periods 1 \
--threshold 0 \
--comparison-operator GreaterThanThreshold \
--treat-missing-data notBreaching \
--alarm-actions "$SNS_TOPIC_ARN" \
--region us-east-1
For Standard Workflows, EventBridge also receives execution status-change events. A rule can match FAILED, TIMED_OUT, or ABORTED and send an event to an SNS topic, Lambda function, or another supported target.
{
"source": ["aws.states"],
"detail-type": [
"Step Functions Execution Status Change"
],
"detail": {
"status": [
"FAILED",
"TIMED_OUT",
"ABORTED"
]
}
}
Apply an additional stateMachineArn filter when you want notifications for a specific workflow. EventBridge delivery is best effort and events may arrive out of order, so downstream processors should tolerate duplicates and ordering differences.
A workflow that catches an error and exits successfully does not increment ExecutionsFailed merely because an internal Task failed. If recovered failures still require attention, emit a separate business metric or notification from the fallback path.
Troubleshoot Step Functions when the Lambda error is not visible
If your execution history shows that Lambda failed but does not provide enough detail, inspect the corresponding Lambda CloudWatch log group. The function logs can reveal application stack traces, dependency failures, timeouts, and the exact request-processing path.
For an optimized Lambda integration, Step Functions commonly receives structured task output. When the Lambda invocation reports a function error, the Task fails and Step Functions can expose the error details in its history.
However, an application can catch its own exception and return a normal JSON response containing an error flag. In that case, Lambda completed successfully from the integration's perspective. You need a Choice state or another explicit check to convert that result into a workflow failure.
Also verify that logs are enabled for the relevant workflow type. Standard Workflows provide execution history through the Step Functions service. Express Workflows rely on configured CloudWatch Logs delivery for execution diagnostics.
When troubleshooting, preserve enough information to correlate the Step Functions execution with the Lambda invocation. Keep secrets, raw authorization headers, passwords and sensitive customer payloads out of your logs.
Design a reliable production error-handling strategy
A reliable workflow uses retries for temporary failures and fallbacks for failures that need an alternative outcome. The goal is not to make every execution turn green. The goal is to preserve business correctness while allowing expected operational problems to recover.
Start by classifying your errors. For example, a supplier API timeout may be temporary, an invalid order may be permanent, and a missing IAM permission may be an infrastructure defect. Each category deserves a different policy.
Next, ensure the error name is predictable. Custom Lambda exceptions can expose stable identifiers for application conditions, allowing targeted ErrorEquals rules. Base your recovery decisions on a dedicated error name where you can, not on fragile text inside the human-readable cause.
Preserve business context through ResultPath. A fallback needs the order identifier, customer identifier, or request correlation key to take meaningful action. Store the cause for operators, but present a controlled message to the customer.
Finally, test failure scenarios deliberately. Inject a temporary API failure, an invalid request, a Lambda timeout, and a permissions failure in a nonproduction environment. Verify that retries occur only where expected and that the workflow ends in the appropriate state.
Jake: "Should every failure end in a Succeed state so customers never see an error?"
Ethan: "No. A booking that was not actually processed should not be marked complete. Recover what you can, preserve the failure when you cannot, and notify the right person."
Frequently asked questions about States.TaskFailed and States.Timeout
What does States.TaskFailed mean in AWS Step Functions?
It means a Task state failed. The underlying cause can be a Lambda exception, integrated-service failure, or another task error. In Retry and Catch matchers, States.TaskFailed also acts as a wildcard for known task errors except States.Timeout.
What is the difference between States.TaskFailed and States.Timeout?
States.TaskFailed describes task failure and serves as a broad task-error matcher. States.Timeout indicates that a task or execution exceeded an applicable timeout. A matcher using only States.TaskFailed does not include States.Timeout.
How do I find the exact Step Functions error message?
Open the failed execution and inspect the failed state in its execution history. Look for the Error and Cause fields. For Standard Workflows, you can also use get-execution-history and describe-execution.
How do I retry only certain errors in Step Functions?
Add a Retry block containing the exact error names under ErrorEquals. Configure IntervalSeconds, MaxAttempts, and BackoffRate. Leave out broad wildcards when some failures are permanent.
Why did my Step Functions Catch block not trigger?
The error might not match ErrorEquals, the catcher might be attached to the wrong state, or the failure might be an uncatchable runtime or top-level execution condition. Check catcher order and whether the fallback itself failed.
Does States.TaskFailed catch States.Timeout?
No. States.TaskFailed acts as a wildcard that excludes States.Timeout. Match States.Timeout separately when you need to handle task timeouts.
Can States.ALL catch every Step Functions error?
No. States.ALL cannot catch States.Runtime or the terminal States.DataLimitExceeded error. It must also appear alone in its matcher list and be the final catcher when used in a Catch array.
How does a Lambda exception appear inside Step Functions?
An unhandled exception in a synchronous Lambda integration causes the task to fail. The state history can include the function error name and cause, while CloudWatch Logs may provide the full stack trace.
How do I pass a Step Functions error to a fallback state?
Use Catch with a matching ErrorEquals, a Next state, and a JSONPath ResultPath such as $.errorInfo. This preserves the original input while adding the error information for the fallback.
How many times does Step Functions retry with MaxAttempts 3?
It allows up to three retries after the initial attempt, giving up to four total attempts. The actual number may be lower if the task succeeds, a different error occurs, or an overall deadline ends the execution.
What is the difference between TimeoutSeconds and HeartbeatSeconds?
TimeoutSeconds limits the allowed task duration. HeartbeatSeconds requires periodic heartbeats for supported tasks and callback patterns. Missing a required heartbeat can fail the task before its overall timeout.
Can a failed Step Functions execution be resumed?
Eligible unsuccessful Standard Workflow executions can be redriven within 14 days. Redrive restarts from the unsuccessful state while preserving previously successful work. It uses the original state machine definition rather than automatically switching to an updated one.
Can Express Workflows use GetExecutionHistory or RedriveExecution?
No. GetExecutionHistory and the Standard execution redrive API do not support Express Workflows. Use CloudWatch Logs for Express execution diagnostics. Some Express child workflows in Distributed Map runs have a separate Map Run recovery mechanism.
How do I alert when Step Functions executions fail?
Create a CloudWatch alarm on the AWS/States ExecutionsFailed metric using the Sum statistic. For Standard Workflows, an EventBridge rule can also match failed, timed-out, or aborted execution status changes and invoke an alerting target.
Why does a Lambda return an error object without failing Step Functions?
Returning an ordinary JSON object such as {"success":false} is still a successful Lambda invocation. Add explicit workflow logic to evaluate the response and transition to an error or fallback path when necessary.
Should I retry States.Permissions or States.Runtime?
Generally, no. Permission errors usually require IAM or resource-policy changes, while States.Runtime indicates a workflow processing error that is not retriable. Correct the underlying problem instead of using repeated attempts.
For readers preparing for an AWS certification
We have been covering AWS certifications alongside our fixes, so here is a short extra for readers studying for one. If you only came for the fix, you already have it; feel free to skip this part.
Exams that test this topic: Developer – Associate (DVA-C03 from December 1, 2026) • Solutions Architect – Associate (SAA-C03) • DevOps Engineer – Professional (DOP-C02).
Here are the exam-style questions this topic tends to raise, with the reasoning you need to answer them:
1. A workflow can run for weeks and needs a full, auditable history of every step. Which workflow type?
A Standard Workflow (executions can run up to one year).
2. Millions of short events must be processed cheaply, each in under five minutes. Which workflow type?
An Express Workflow.
3. A Lambda task gets throttled now and then. How do you retry it with growing delays?
A Retry rule with IntervalSeconds, BackoffRate and MaxAttempts for the throttling error.
4. A workflow must pause until a person approves an order. Which pattern?
The callback pattern with a task token (.waitForTaskToken).
5. Thousands of S3 objects must be processed in parallel by one workflow. What do you use?
A Distributed Map state.
6. A Standard execution failed at step 7 of 10. How do you continue from step 7 instead of starting over?
Redrive the execution (within 14 days of its failure).
7. Operations must hear about every failed execution. What do you set up?
An EventBridge rule on Step Functions execution status changes, or a CloudWatch alarm on ExecutionsFailed.
Exam codes and dates change often. Our AWS certification changes page keeps track of what is current.
For Jake's repair-booking workflow, the fix was not to restart every failed execution or add endless retries. The reliable approach was to identify the supplier API failure, give temporary errors a bounded retry policy, preserve order details for a fallback, and alert when recovery could not finish automatically.
If your Step Functions execution shows States.TaskFailed or States.Timeout, start with the execution history and the exact error name. Once you know what failed, you can decide whether the workflow should retry, recover, stop, or request human intervention. I hope your next failed execution provides a clear path to the real problem rather than another round of guessing.
📌 If you keep one line from this page
Read Error and Cause first, retry only recoverable failures, and preserve the original input when routing failures to a fallback.
Revision note. Written October 19, 2026. "If at first you don't succeed, try, try again," the saying goes; Step Functions adds: but only for the errors that can succeed.