The DVA-C02 expects you to recognize when AWS Step Functions is the right tool — “coordinate multiple steps with branching and error handling” points to a state machine, not a tangle of queues and glue code. That decision, and how Step Functions sits alongside SQS, SNS, and EventBridge, is covered in the event-driven architecture guide. This post goes one level deeper into the part the exam quietly assumes you can do: actually author, wire, and debug a state machine — the workflow types, the Amazon States Language, how data flows between states, how errors are handled declaratively, and how a task waits for a job or a human.
Get these mechanics right and a whole band of DVA-C02 questions — the ones with a snippet of state-machine JSON and a “what happens to the output” or “why does this retry” prompt — become straightforward.
Standard vs Express: The First Decision
Every state machine is created as one of two immutable types. The type is set at creation and cannot be changed afterward, so choosing correctly matters, and the exam probes the differences constantly.
| Dimension | Standard | Express |
|---|---|---|
| Maximum duration | 1 year | 5 minutes |
| Execution semantics | Exactly-once | Asynchronous: at-least-once; Synchronous: at-most-once |
| Execution history | Recorded by Step Functions (visible in console/API), 90 days | Only via CloudWatch Logs (must enable logging) |
| Pricing | Per state transition | Per number of executions + duration + memory |
| Service integration patterns | Request Response, Run a Job (.sync), Wait for Callback (.waitForTaskToken) | Request Response only |
| Distributed Map / Activities | Supported | Not supported |
| Best for | Long-running, auditable, non-idempotent work (payments, EMR jobs) | High-volume, short, idempotent event processing |
Two nuances candidates miss:
- Express is not one flavor. Asynchronous Express returns immediately (you poll CloudWatch Logs for the result) and is at-least-once, so a step can run more than once — fine for idempotent work like a DynamoDB
PutItem. Synchronous Express (started withStartSyncExecution, e.g. behind API Gateway) waits and returns the result and is at-most-once. The blanket “Express is at-least-once” you may have memorized is only half the story. - Standard is exactly-once, which is why it is the answer for non-idempotent actions — charging a card, starting a cluster — where running a step twice would be harmful.
The Amazon States Language and Its State Types
A state machine is defined in JSON using the Amazon States Language (ASL). You should be able to read a definition and name each state’s job. There are eight state types:
| State type | What it does |
|---|---|
Task | Does work — invokes a Lambda function or an integrated AWS service |
Choice | Branches based on conditions (the if/switch of a workflow) |
Parallel | Runs multiple branches concurrently and joins their results |
Map | Runs the same steps for each item in an array |
Wait | Delays for a duration or until a timestamp |
Pass | Passes input to output (optionally injecting fixed data); useful for testing |
Succeed | Stops the execution successfully |
Fail | Stops the execution with an error name and cause |
A minimal Task → Choice skeleton looks like this:
{
"Comment": "Validate then charge",
"StartAt": "Validate",
"States": {
"Validate": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "validateOrder", "Payload.$": "$" },
"Next": "IsValid" },
"IsValid": { "Type": "Choice",
"Choices": [ { "Variable": "$.valid", "BooleanEquals": true, "Next": "Charge" } ],
"Default": "HandleFailure" },
"Charge": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "chargeCard", "Payload.$": "$" }, "End": true },
"HandleFailure": { "Type": "Fail", "Cause": "ValidationFailed" }
}
}
Note StartAt, the per-state Next/End, and the .$ suffix on Payload.$ — that suffix means “the value is a path into the state’s data,” which brings us to how data actually flows.
Processing Input and Output
This is the single most testable Step Functions mechanic at the developer level. Each state receives JSON input and produces JSON output, and for the classic JSONPath query language, five fields transform the data in a fixed order:
InputPath → Parameters → (task runs) → ResultSelector → ResultPath → OutputPath
InputPath— selects which part of the raw input to use.Parameters— builds the exact structure sent to the task (this is where"Payload.$": "$"lives).ResultSelector— picks/reshapes fields out of the task’s result.ResultPath— decides where the result is placed relative to the original input.ResultPath: "$.result"keeps the input and nests the result underresult; omit it and the result replaces the input.OutputPath— filters the combined structure down to what the next state receives.
The one that trips people up is ResultPath: if a question shows an input object, a task result, and asks “what does the next state see,” the answer hinges on whether ResultPath merged the result into the input or overwrote it. Memorize the order and that rule.
Newer state machines can opt into JSONata instead of JSONPath by setting
QueryLanguage. AWS now recommends JSONata for new workflows; it replaces the five-field pipeline withArguments,Output, andAssignfields and lets you read state with$states.input. Existing state machines default to JSONPath for backward compatibility. Know that JSONata exists and is the recommended default going forward, but the JSONPath pipeline above is still the model most exam snippets use.
Error Handling: Retry and Catch
Step Functions gives you declarative error handling so you do not scatter retry loops through your Lambda code. Two fields on a Task (or Parallel/Map) state do the work.
Retry retries the state on matching errors with exponential backoff:
"Retry": [
{ "ErrorEquals": ["States.TaskFailed"],
"IntervalSeconds": 2, "MaxAttempts": 3, "BackoffRate": 2.0 }
]
IntervalSeconds is the first wait, MaxAttempts the retry count, and BackoffRate the multiplier applied each attempt (2, then 4, then 8 seconds here). This mirrors the retry-with-backoff pattern you would otherwise hand-code — see the SDK retries and exponential backoff guide — but managed by the workflow.
Catch routes to a fallback state when an error is not (or is no longer) retried:
"Catch": [
{ "ErrorEquals": ["States.ALL"], "ResultPath": "$.error", "Next": "Cleanup" }
]
The exam expects you to know the predefined error names: States.ALL (any error), States.TaskFailed, States.Timeout, States.Permissions, and others. States.ALL must be the last retrier or catcher because it matches everything. Using ResultPath inside Catch to preserve the error under $.error (rather than discarding the original input) is a common “which output” question.
Service Integration Patterns
A Task can call a service in one of three integration patterns, chosen by a suffix on the Resource ARN. This is heavily tested, and each pattern behaves differently.
| Pattern | ARN suffix | Behavior |
|---|---|---|
| Request Response (default) | (none) | Call the service, get the HTTP response, move to the next state immediately |
| Run a Job | .sync | Call the service and wait for the job to complete before continuing |
| Wait for Callback | .waitForTaskToken | Pause until an external process returns a task token |
Run a Job (.sync) is for services with long-running work — AWS Batch, ECS/Fargate tasks, AWS Glue, EMR, a nested Step Functions execution. arn:aws:states:::batch:submitJob.sync submits the job and the state pauses until Batch reports done.
Wait for Callback (.waitForTaskToken) is the pattern for human approvals, third-party callbacks, and legacy integrations. You embed a task token in the outbound call and the state pauses — potentially for up to the one-year execution limit — until something calls back:
"WaitForApproval": {
"Type": "Task",
"Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
"Parameters": {
"QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/approvals",
"MessageBody": { "orderId.$": "$.orderId", "TaskToken.$": "$$.Task.Token" }
},
"Next": "Fulfill"
}
The token comes from the Context object via $$.Task.Token (the double $$ accesses execution context, not state data). The external worker resumes the workflow by calling SendTaskSuccess (with a result payload) or SendTaskFailure. To avoid a task hanging forever, set a HeartbeatSeconds timeout and have the worker call SendTaskHeartbeat; miss the heartbeat window and the task fails with States.Timeout.
Critical exam fact: Express workflows support only Request Response. Neither .sync nor .waitForTaskToken works in Express. If a scenario needs to wait for a job or a callback, the answer is a Standard workflow.
Map and Distributed Map
A Map state runs the same steps for each element of an input array. The inline Map runs iterations within the parent execution and is fine for modest arrays. Distributed Map is a mode built for massive parallelism — up to 10,000 parallel child executions and datasets read straight from Amazon S3 (millions of objects) — and it is Standard-only (Express does not support Distributed Map). For the DVA-C02, know that inline Map handles ordinary “process each item” work; the large-scale, S3-driven fan-out architecture is more of a Solutions Architect Professional concern, covered in the SAP-C02 serverless architecture patterns guide. Keep your developer focus on the inline mechanics.
Developer Tooling: SAM, X-Ray, and TestState
Building and shipping state machines is squarely a developer task, so know the tooling:
- AWS SAM defines a state machine as
AWS::Serverless::StateMachine, with the ASL kept in a separate definition file and referenced byDefinitionUri— the same infrastructure-as-code workflow as the rest of your serverless app. See the SAM serverless deployments guide for the deployment mechanics. - AWS X-Ray integrates with Step Functions for distributed tracing across the workflow and its downstream services — the answer when a question asks how to trace a slow or failing multi-step workflow. It complements the CloudWatch metrics and logs covered in the monitoring and troubleshooting guide.
TestStateis an API that tests a single state in isolation — you pass sample input and inspect the output and the applied input/output processing without running the whole machine. It is the fast way to debug aResultPathorChoicerule.- Versions and aliases let you publish immutable versions of a state machine and shift traffic with an alias, mirroring the pattern you already use for Lambda versions, aliases, and concurrency.
Decision Cheat Sheet and Exam Traps
| Scenario wording | Points to |
|---|---|
| ”Non-idempotent step must never run twice” | Standard (exactly-once) |
| “High-volume, short, idempotent event processing, cheapest” | Express (asynchronous) |
| “Synchronous response behind API Gateway” | Synchronous Express (StartSyncExecution) |
| “Wait for an AWS Batch / ECS / Glue job to finish” | .sync on a Standard workflow |
| ”Pause for a human approval or third-party callback” | .waitForTaskToken + SendTaskSuccess (Standard) |
| “Preserve the original input alongside a task’s result” | ResultPath merges the result |
| ”Retry transient failures automatically with backoff” | Retry with BackoffRate |
| ”Send failures to a cleanup branch” | Catch with States.ALL last |
Recurring traps: choosing Express when the workflow needs .sync or .waitForTaskToken (unsupported in Express); forgetting that ResultPath omitted means the result replaces the input; putting States.ALL before more specific error matchers; and assuming Standard and Express are interchangeable after creation (the type is immutable).
Frequently Asked Questions
When should I use Standard vs Express workflows on the DVA-C02?
Use Standard for long-running (up to a year), auditable, non-idempotent work where exactly-once matters — payments, orchestrating cluster jobs — and whenever you need the .sync or .waitForTaskToken integration patterns. Use Express for high-volume, short (≤5 minute), idempotent event processing where cost and throughput matter. Remember Synchronous Express is at-most-once while Asynchronous Express is at-least-once.
What is the difference between InputPath, Parameters, ResultSelector, ResultPath, and OutputPath?
They are the five JSONPath fields that transform data through a state, applied in that order. InputPath selects input; Parameters builds what the task receives; ResultSelector reshapes the task result; ResultPath decides where the result is placed relative to the input (merge vs replace); OutputPath filters what the next state gets. ResultPath is the most commonly tested because it controls whether the original input survives.
How do Retry and Catch differ?
Retry re-attempts the same state on matching errors using IntervalSeconds, MaxAttempts, and BackoffRate for exponential backoff. Catch gives up on the state and transitions to a fallback state when an error matches. A state can have both — retry first, then catch what still fails. List States.ALL last in either.
What does .waitForTaskToken do?
It pauses a task until an external process calls back. Step Functions passes a task token (via $$.Task.Token) in the outbound request; the worker later calls SendTaskSuccess or SendTaskFailure with that token to resume the workflow. Use HeartbeatSeconds and SendTaskHeartbeat to avoid waiting indefinitely. It is supported only in Standard workflows.
Can Express workflows use the .sync or callback patterns?
No. Express workflows support only the Request Response pattern. If you need to wait for a job (.sync) or a callback (.waitForTaskToken), you must use a Standard workflow.
Conclusion
Step Functions questions on the DVA-C02 reward developers who can read a state machine, not just name the service. Anchor on four things: the Standard vs Express split (exactly-once vs at-least-once/at-most-once, and the fact that only Standard supports .sync and .waitForTaskToken); the ASL state types and how a Task calls work; the input/output pipeline, especially how ResultPath merges or replaces; and the error-handling fields Retry and Catch with the predefined error names. Layer on the integration patterns and the SAM/X-Ray/TestState tooling and you can answer the snippet-based questions with confidence.
The reliable way to make these mechanics automatic is timed practice on questions that show real ASL and ask “what happens next.” Sailor.sh’s AWS Certified Developer - Associate (DVA-C02) Certification-Ready Mock Exam Bundle drills exactly these serverless-orchestration scenarios with explanations that reinforce why an output looks the way it does or why a workflow retried. Pair the mocks with the DVA-C02 exam guide for 2026 and the study plan, and treat every Step Functions question you miss as a chance to sharpen your reading of the state language.