Back to Blog

AWS Lambda Event Source Mappings for the DVA-C02 Exam: Batching Windows, Partial Batch Responses, Stream Error Handling, Filtering & Concurrency Controls

A developer's guide to Lambda event source mappings for the AWS Certified Developer - Associate (DVA-C02) exam. Learn how Lambda polls SQS, Kinesis and DynamoDB Streams on your behalf, what batch size and batching window really control, how ReportBatchItemFailures stops successful records from being reprocessed, how bisect-on-error, maximum retry attempts, maximum record age and on-failure destinations unblock a poisoned shard, how event filtering drops records before invocation, and how parallelization factor and maximum concurrency govern scale.

By Sailor Team , October 8, 2026

Most DVA-C02 candidates know that Lambda can be triggered by an SQS queue, a Kinesis stream or a DynamoDB stream. Far fewer can explain what happens between “a record arrives” and “my handler runs”: who polls, how records are grouped into a batch, what Lambda does when the batch fails, and why one setting on the queue and another on the function decide whether a bad message blocks everything behind it. That machinery is the event source mapping (ESM), and the exam tests its parameters directly.

This guide is written for the Development with AWS Services domain (32% of the exam), where ESM questions cluster. The Lambda versions, aliases and concurrency guide introduces the push-versus-poll distinction and the SQS, SNS and EventBridge guide covers queue parameters such as visibility timeout and redrive policies. Here we go one level down into the mapping itself.

What an Event Source Mapping Is (and Is Not)

Lambda has two invocation families. Push sources such as S3, SNS, API Gateway and EventBridge call Lambda’s Invoke API themselves. Poll sources cannot, so Lambda runs the poller for you: an event source mapping is a Lambda-managed resource that reads from the source, assembles records into a batch, and invokes your function synchronously with that batch as the event.

Poll-based sources that use an ESM:

SourceOrdering unitLambda invokes withTypical exam angle
Amazon SQS (standard and FIFO)Message group (FIFO only)A batch of messagesVisibility timeout, partial batch responses, maximum concurrency
Amazon Kinesis Data StreamsShardA batch of records in sequence orderBlocked shards, bisect, retry and record age limits
Amazon DynamoDB StreamsShardA batch of change recordsSame as Kinesis, plus NewImage/OldImage filtering
Amazon MSK and self-managed Apache KafkaPartitionA batch of Kafka recordsAuthentication via Secrets Manager, VPC access
Amazon MQ (ActiveMQ, RabbitMQ)QueueA batch of messagesBroker credentials in Secrets Manager
Amazon DocumentDBChange streamA batch of change eventsRarely tested beyond recognition

Two consequences shape everything else in this article. Because the invocation is synchronous, asynchronous features such as function-level dead-letter queues and Lambda destinations do not apply to ESM invocations; error handling lives on the mapping (for streams) or on the source (for SQS). And because Lambda is the consumer, the function’s execution role needs read permissions on the source: sqs:ReceiveMessage, sqs:DeleteMessage and sqs:GetQueueAttributes for a queue, or kinesis:GetRecords, kinesis:GetShardIterator, kinesis:DescribeStream and kinesis:ListShards for a stream. The AWSLambdaSQSQueueExecutionRole and AWSLambdaKinesisExecutionRole managed policies bundle these, which is why “the mapping shows an error about permissions” questions are answered by the function role, not the queue policy.

Creating a mapping is a single call:

aws lambda create-event-source-mapping \
  --function-name order-processor \
  --event-source-arn arn:aws:kinesis:us-east-1:111122223333:stream/orders \
  --starting-position LATEST \
  --batch-size 100 \
  --maximum-batching-window-in-seconds 5

Mappings have a lifecycle (Creating, Enabled, Disabling, Disabled, Updating, Deleting). Disabling a stream mapping pauses polling but keeps the checkpoint, so re-enabling resumes where it stopped rather than from the starting position. That detail answers the “we need to pause processing during a maintenance window without losing records” scenario.

Batch Size and Batching Window: What Actually Triggers an Invocation

A batch is sent to the function when any of three conditions is met first:

  1. The batch reaches batch size records.
  2. The maximum batching window (0 to 300 seconds) expires.
  3. The payload reaches Lambda’s 6 MB synchronous payload limit.

Defaults and ceilings differ per source, and the exam likes the edges:

SourceDefault batch sizeMaximum batch sizeBatching window
SQS standard1010,0000 to 300 s; a window of at least 1 s is required for batch sizes above 10
SQS FIFO10100 to 300 s
Kinesis Data Streams10010,0000 to 300 s
DynamoDB Streams10010,0000 to 300 s

The trade-off is cost against latency. A larger batch and a longer window mean fewer invocations and better amortized overhead, but records wait longer before processing. “Reduce the number of Lambda invocations for a low-volume stream” is solved by raising the batching window; “process records within a second of arrival” is solved by a window of 0.

For streams, remember what the batch is not: it never mixes records from different shards, and records inside it are in sequence-number order. Your function receives them in order and, unless you opt into partial batch responses, is expected to either succeed on all of them or fail the batch.

The SQS Side: Visibility, Deletion and Why the DLQ Belongs to the Queue

For SQS, the ESM long-polls the queue, hands the batch to your function, and deletes the messages only if the invocation succeeds. If the function throws, Lambda deletes nothing; the messages become visible again when the queue’s visibility timeout expires, and a later poll picks them up. Lambda itself performs no retries for SQS. Retries are an emergent property of the queue.

Three implications follow, and each is a frequent question:

  • Set the queue’s visibility timeout to at least six times the function timeout. Lambda recommends this so that a batch has time to be processed, plus room for the ESM’s own retry behaviour, before the messages reappear. A visibility timeout shorter than the function timeout is the most common cause of “messages are processed twice”.
  • Poison messages go to a dead-letter queue through the source queue’s redrive policy (maxReceiveCount), not through a Lambda DLQ. The function-level dead-letter configuration only applies to asynchronous invocations. Putting a DLQ on the function and expecting SQS failures to land there is a trap the exam sets regularly.
  • Processing is at-least-once. Even with a correct visibility timeout, network partitions and duplicate deliveries happen, so handlers must be idempotent, typically by recording processed message IDs in DynamoDB with a conditional write as the DynamoDB guide describes.

FIFO queues

A FIFO mapping preserves order per message group. Lambda scales the number of concurrent batches up to the number of active message groups, and if a message in a group fails, Lambda stops processing further messages from that group until the failure is resolved or the message is moved to the DLQ. Batch size is capped at 10 so that a single group’s ordering can be honoured.

SQS scaling and maximum concurrency

For standard queues, the ESM starts with five concurrent invocations and adds up to 300 per minute as the backlog grows, up to a ceiling of 1,250 concurrent invocations per mapping. That is often more than a downstream database can take. Two ways to cap it exist, and the exam expects you to pick the right one:

  • Reserved concurrency on the function caps all invocations of that function, but when the ESM exceeds it the extra invocations are throttled. Throttled batches are not deleted, their messages return to the queue after the visibility timeout, and the receive count increments, which means a correctly working message can be driven into the DLQ purely by throttling.
  • Maximum concurrency on the event source mapping (ScalingConfig.MaximumConcurrency, 2 to 1,000) tells the ESM to stop polling beyond that number of concurrent batches. No throttling, no inflated receive counts, and it applies per mapping, so two queues feeding the same function can have different ceilings.
aws lambda update-event-source-mapping \
  --uuid 8f3c1e2a-1234-4a5b-9c6d-0e1f2a3b4c5d \
  --scaling-config '{"MaximumConcurrency": 20}'

“Limit how many messages a function processes concurrently from a queue without causing messages to be sent to the DLQ” is answered by maximum concurrency on the mapping.

Partial Batch Responses: Stop Reprocessing the Records That Succeeded

By default a batch is all-or-nothing. If message 7 of 10 throws, Lambda reports the invocation as failed, and all 10 SQS messages become visible again (or, for a stream, the whole batch is retried). Records 1 to 6 are processed twice. The fix is partial batch responses, enabled by setting FunctionResponseTypes to ReportBatchItemFailures on the mapping and returning a specific JSON shape from the handler:

aws lambda update-event-source-mapping \
  --uuid 8f3c1e2a-1234-4a5b-9c6d-0e1f2a3b4c5d \
  --function-response-types ReportBatchItemFailures
def handler(event, context):
    failures = []
    for record in event["Records"]:
        try:
            process(record)
        except Exception:
            failures.append({"itemIdentifier": record["messageId"]})
    return {"batchItemFailures": failures}

The identifier differs by source: messageId for SQS, and the record’s sequenceNumber for Kinesis and DynamoDB Streams (found at record["kinesis"]["sequenceNumber"] or record["dynamodb"]["SequenceNumber"]). Lambda then behaves as follows:

  • SQS: only the messages listed in batchItemFailures stay in the queue; everything else is deleted. An empty list means total success.
  • Streams: Lambda checkpoints to the lowest sequence number you reported as failed and retries from there. Records before it are considered done; records after it are retried together with the failed one, because order must be preserved within the shard.
  • Invalid responses are treated as total failure. Returning malformed JSON, or a batchItemFailures entry with an empty or null itemIdentifier, makes Lambda retry the whole batch. Returning null or an empty object is treated as success.

For FIFO queues, once the first failure is recorded, Lambda does not continue processing the rest of the batch; it returns the remaining messages too, so group ordering survives.

The exam phrase that maps to this feature is almost always “some records in a batch fail and the successful ones are being processed again”. If you see it, the answer involves ReportBatchItemFailures, not a smaller batch size.

Stream Error Handling: Unblocking a Poisoned Shard

Streams have a problem SQS does not. Records in a shard are ordered, so Lambda cannot skip a failing batch and move on. The default behaviour is to retry the same batch until it succeeds or the records expire from the stream’s retention period (24 hours by default for Kinesis, extendable to 365 days). One malformed record, one “poison pill”, stalls the entire shard while every later record ages behind it. You see this as a climbing IteratorAge metric in CloudWatch, which the monitoring and troubleshooting guide covers.

Four mapping-level settings bound the damage. Learn them as a group, because the exam will offer them as distractors for each other:

SettingRangeWhat it does
BisectBatchOnFunctionErrortrue/falseOn failure, split the batch in two and retry each half; keeps splitting until the bad record is isolated
MaximumRetryAttempts-1 (infinite, default) to 10,000Give up on a batch after this many retries
MaximumRecordAgeInSeconds-1 (no limit, default) to 604,800 (7 days)Discard records older than this instead of retrying them
DestinationConfig.OnFailureSQS queue or SNS topicWhere to send the record of a discarded batch
aws lambda update-event-source-mapping \
  --uuid 8f3c1e2a-1234-4a5b-9c6d-0e1f2a3b4c5d \
  --bisect-batch-on-function-error \
  --maximum-retry-attempts 3 \
  --maximum-record-age-in-seconds 3600 \
  --destination-config '{"OnFailure":{"Destination":"arn:aws:sqs:us-east-1:111122223333:orders-stream-failures"}}'

Two details separate a pass from a fail on these questions:

  1. The on-failure destination receives metadata, not the records. The message delivered to the SQS queue or SNS topic contains the shard ID, the start and end sequence numbers, the approximate arrival times, the batch size and the stream ARN, so you can fetch the records yourself with GetRecords before they expire. It does not contain the record payloads. If a question says “the DLQ for the stream contains the failed records”, that statement is wrong.
  2. Bisecting is a diagnostic multiplier, not a retry limit. With bisect enabled and a batch of 100, Lambda tries 100, then 50, then 25, and so on, until a batch of 1 isolates the poison record. Each split counts against MaximumRetryAttempts, and records in the good halves are processed again, so bisect pairs naturally with ReportBatchItemFailures and idempotent handlers.

These four settings exist only for Kinesis and DynamoDB Streams mappings. Offering “set maximum retry attempts on the SQS mapping” is a distractor; SQS uses the queue’s redrive policy instead.

Starting Position, Enhanced Fan-Out and Checkpointing

A stream mapping needs to know where to begin. StartingPosition accepts TRIM_HORIZON (the oldest record still in the stream), LATEST (only records written after the mapping was created), and, for Kinesis only, AT_TIMESTAMP with a StartingPositionTimestamp. DynamoDB Streams supports just the first two. After the first read, Lambda maintains its own checkpoint per shard; the starting position only matters when the mapping is created.

A Kinesis mapping reads through the shared 2 MB per second per shard throughput by default, competing with every other consumer. Point the mapping at a registered enhanced fan-out consumer ARN instead of the stream ARN and Lambda gets a dedicated 2 MB per second pipe over HTTP/2 push, which is the answer to “multiple consumers are causing ReadProvisionedThroughputExceeded errors”. The Kinesis Data Streams guide explains the consumer models in depth.

Parallelization Factor and Tumbling Windows

By default a stream mapping runs one concurrent batch per shard, so a 10-shard stream drives at most 10 concurrent invocations. That is the ordering guarantee doing its job, and it caps throughput. ParallelizationFactor (1 to 10) lets Lambda run up to 10 concurrent batches per shard while still processing records with the same partition key in order, because Lambda groups records by partition key before fanning them out. A 10-shard stream with a factor of 10 can reach 100 concurrent invocations without resharding, which is cheaper and faster than adding shards when the bottleneck is function latency rather than ingest throughput.

Tumbling windows solve a different problem: aggregating a stream over time without an external store. Setting TumblingWindowInSeconds (up to 900, or 15 minutes) makes Lambda invoke the function repeatedly for the window, passing a state object from one invocation to the next and marking the final invocation with isFinalInvokeForWindow: true. The function returns {"state": {...}} after each batch and performs its aggregate action on the final call. It is the exam’s answer to “compute a per-minute total from a stream using only Lambda”.

Event Filtering: Drop Records Before You Pay for Them

Many functions begin with if record.type != "ORDER_CREATED": continue. Lambda can do that check for you. FilterCriteria on the mapping accepts up to five filter patterns (raiseable by quota request) using the same pattern syntax as EventBridge rules: exact values, prefix, numeric ranges, exists, and anything-but. Records that match no filter are never sent to the function, which saves invocations and keeps handlers focused.

aws lambda update-event-source-mapping \
  --uuid 8f3c1e2a-1234-4a5b-9c6d-0e1f2a3b4c5d \
  --filter-criteria '{"Filters":[{"Pattern":"{\"data\":{\"type\":[\"ORDER_CREATED\"],\"total\":[{\"numeric\":[\">\",100]}]}}"}]}'

Where the pattern applies depends on the source, and the exam expects you to know the field:

SourceField the filter inspectsNotes
SQSbodyIf the body is JSON, filter on its keys; otherwise only string matching on the raw body works
KinesisdataLambda base64-decodes the payload and parses it as JSON for matching
DynamoDB Streamsdynamodb (for example dynamodb.NewImage.status.S) and eventNameFilter on INSERT, MODIFY, REMOVE, or on attribute values in DynamoDB JSON format
Kafka and MQvalueDecoded similarly to Kinesis

One asymmetry matters. For SQS, messages that fail the filter are deleted from the queue by the ESM; they are not left for another consumer. For streams, non-matching records are simply skipped and the checkpoint advances past them. If a question describes a second application that needs the filtered-out messages, filtering at the mapping is the wrong design and SNS fan-out with message filtering (from the event-driven guide) is the right one.

Kafka and MQ Mappings in One Paragraph

The exam goes no deeper than recognition here. A mapping to Amazon MSK or self-managed Kafka specifies a topic, a consumer group, and SourceAccessConfigurations that reference a Secrets Manager secret for SASL/SCRAM or mutual TLS, plus VPC subnets and security groups for self-managed clusters. Amazon MQ mappings work the same way with broker credentials in Secrets Manager. Kafka mappings also support a provisioned mode with a configurable number of event pollers for predictable throughput. If a question mentions a Kafka topic and Lambda, the answer involves an event source mapping and a Secrets Manager secret, not an SDK consumer loop inside the function.

Observability for Mappings

Three signals tell you whether a mapping is healthy:

  • IteratorAge (Kinesis and DynamoDB Streams): how far behind the latest record the mapping is reading. A rising value means a blocked shard or an under-provisioned function.
  • ApproximateAgeOfOldestMessage (SQS): the same idea for queues.
  • Enhanced ESM metrics, an opt-in setting on the mapping (MetricsConfig) that emits counts of events polled, filtered out, invoked, failed, dropped and delivered to the on-failure destination, so you can see exactly where records went instead of inferring it from function errors.

Pair these with Errors and Throttles on the function itself. An ESM question that says “the function reports no errors but the stream is falling behind” is pointing at throttling, concurrency limits, or a batch window that is too long.

Exam Scenario Cheat Sheet

Scenario wordingAnswer
Successful SQS messages reprocessed when one in the batch failsReportBatchItemFailures and return batchItemFailures
Messages processed more than onceVisibility timeout ≥ 6× function timeout; idempotent handler
Poison SQS message blocks the queueRedrive policy with maxReceiveCount on the source queue
Cap concurrency from a queue without sending messages to the DLQESM maximum concurrency, not reserved concurrency
One bad Kinesis record stalls the shardBisect on error, maximum retry attempts, maximum record age, on-failure destination
Need to capture which records were discarded from a streamOn-failure destination (metadata only, fetch records with GetRecords)
Need more throughput per shard without reshardingParallelizationFactor up to 10
Compute a rolling aggregate from a streamTumbling window with state
Avoid invoking the function for irrelevant recordsFilterCriteria on the mapping
Multiple consumers hit read throughput limitsEnhanced fan-out consumer ARN on the mapping
Pause stream processing without losing positionDisable the mapping
Reduce invocations for a trickle of recordsRaise MaximumBatchingWindowInSeconds
Mapping fails with a permissions errorAdd source read permissions to the function execution role

Practice Against Parameter-Level Questions

Event source mapping questions are unusual on the DVA-C02 because the correct answer is often a specific setting name, and the distractors are its neighbours: reserved versus maximum concurrency, a queue redrive policy versus a function DLQ, bisect versus record age. Reading about them once is not enough; you need to be wrong on a few timed questions and read why. Sailor.sh’s AWS Certified Developer - Associate (DVA-C02) Mock Exam Bundle contains eight full-length mock exams whose serverless scenarios are written at this parameter level, with explanations that spell out which mapping setting applies and why the alternatives fail. Combine it with the DVA-C02 practice questions and the serverless guide to see how mappings sit alongside the rest of the Lambda material, and with the SAM deployments guide to define mappings as Events in a template rather than by hand.

Frequently Asked Questions

Does an event source mapping invoke Lambda synchronously or asynchronously?

Synchronously. The ESM waits for the function’s response to decide whether to delete the SQS messages or advance the stream checkpoint. That is why asynchronous-only features such as function destinations and the function-level DLQ do not apply to mapped sources.

Can I use ReportBatchItemFailures with every source?

It is supported for SQS, Kinesis Data Streams and DynamoDB Streams. For Kafka and MQ sources the whole batch is still treated as a unit, so handlers there should catch and record per-record failures themselves.

Why does Lambda recommend a visibility timeout of six times the function timeout?

Because a batch can take the full function timeout, Lambda’s poller may need time to retry the invocation, and the messages must stay invisible throughout. Six times the timeout gives enough margin that a message is not handed to a second invocation while the first is still working on it.

What is the difference between MaximumRetryAttempts and MaximumRecordAgeInSeconds?

Retry attempts count how many times a batch may be re-invoked after failure. Record age is a time bound on the records themselves, measured from when they entered the stream. Either limit being exceeded causes the batch to be discarded and, if configured, reported to the on-failure destination. Use retries when the failure is likely transient; use record age when stale data is worthless, such as a real-time dashboard.

If I set a filter on an SQS mapping, what happens to messages that do not match?

The mapping deletes them from the queue. They are not retained for other consumers, so use mapping-level filtering only when the function is the sole consumer of that queue.

How many concurrent invocations can a stream mapping drive?

Number of shards multiplied by the parallelization factor, capped by the function’s available concurrency. Ten shards with a factor of 1 give at most 10; with a factor of 10, at most 100.

Does disabling a mapping lose records?

No. For streams the checkpoint is retained and the records remain in the stream until the retention period expires; for SQS the messages simply sit in the queue. Deleting a mapping, by contrast, discards the checkpoint, and a replacement mapping starts from its configured starting position.

Conclusion

An event source mapping is Lambda doing the consumer’s job for you, and every parameter on it answers a question about how much work the function should receive, how long it should wait, and what should happen when something breaks. For the DVA-C02 exam, the lines to hold are: batch size and batching window decide when a batch is sent; SQS retries come from the queue’s visibility timeout and redrive policy, not from Lambda; ReportBatchItemFailures stops successful records from being reprocessed; bisect, maximum retries, maximum record age and an on-failure destination unblock a poisoned shard; filtering drops records before you pay for them; and parallelization factor and maximum concurrency govern how fast the mapping can go. Learn those as mechanisms rather than as a list, and the parameter-name questions become the easiest marks on the paper.

Read the DVA-C02 exam guide for where serverless integration sits in the overall blueprint, and test these settings against a timed mock exam before you book the real thing.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now