Provided list of item keys contains duplicates (BatchWriteItem)
TL;DR — Your BatchWriteItem request contains two or more operations on the same primary key (two puts of one key, or a put and a delete of it). A single batch can't act on one item more than once, so DynamoDB rejects the entire batch. Collapse duplicates to one operation per key before sending.
What it means
ValidationException: Provided list of item keys contains duplicatesBatchWriteItem performs up to 25 put/delete operations. Every operation in the request must target a distinct primary key. If two PutRequest/DeleteRequest entries resolve to the same key (partition key, or partition + sort key), DynamoDB fails the whole call with this HTTP 400 ValidationException — nothing is written. It's not retryable unchanged.
Why it happens
- The same item put twice in one batch — commonly when a source list has duplicate records and you map each to a
PutRequest. - A put and a delete of the same key in the same batch — still two operations on one item, still rejected.
- Building batches without de-duping across a stream of events that repeat a key.
- Composite-key oversight — two rows you thought were distinct share partition + sort key.
- ETL / bulk-load jobs (Glue, custom importers) that don't merge by key before chunking.
How to fix it
- Collapse to one operation per key, keeping the last write wins:
import {marshall} from '@aws-sdk/util-dynamodb'; const byKey = new Map(); for (const item of records) { byKey.set(`${item.pk}#${item.sk ?? ''}`, {PutRequest: {Item: marshall(item)}}); } const batch = [...byKey.values()]; // <= one op per key - Use boto3's
overwrite_by_pkeysif you use the Pythonbatch_writer—batch_writer(overwrite_by_pkeys=['pk', 'sk'])drops a buffered request when a newly added item has the same primary key, so the last write for each key wins. - Chunk to 25 operations per
BatchWriteItemafter de-duping, and retryUnprocessedItems(throttling — a separate concern). - Need to write then delete the same key? Split them across separate requests, or use
TransactWriteItems(which also forbids two actions on one item, but makes the intent explicit).
Inspecting a bulk load before you run it? The DynoTable desktop app shows items by key so duplicate keys queued for the same batch stand out.
Reproduce it
A BatchWriteItem containing the same primary key twice:
await client.send(
new BatchWriteItemCommand({
RequestItems: {
orders: [
{PutRequest: {Item: {pk: {S: 'DUP'}, sk: {S: 'META'}}}},
{PutRequest: {Item: {pk: {S: 'DUP'}, sk: {S: 'META'}}}}
]
}
})
);Real output:
ValidationException: Provided list of item keys contains duplicates
HTTP 400The whole batch is rejected — neither write lands. Because a batch has no ordering guarantee, DynamoDB will not decide which of the two duplicates should win, so de-duplicate by key before building the request.
Related errors
- Provided list of item keys contains duplicates (BatchGetItem) — the same rule on the read path.
- ConditionalCheckFailedException — a per-item guard that failed at write time.
- Code example: BatchWriteItem in Node.js — a correct chunked batch write to adapt.
- Learn: Batch operations
References
- BatchWriteItem — Amazon DynamoDB API Reference
- Amazon DynamoDB — AWS SDK for Python (Boto3) guide (batch_writer / overwrite_by_pkeys)
- TransactWriteItems — Amazon DynamoDB API Reference
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.
Reproduced 2026-07-26 against DynamoDB Local 2.x with AWS SDK for JavaScript v3.1095.0 — the output above is verbatim.