DuplicateItemException: duplicate primary key
TL;DR — A PartiQL INSERT is a strict create: if an item with the same primary key already exists, DynamoDB throws DuplicateItemException instead of overwriting it. To modify the existing item use PartiQL UPDATE; to get PutItem's replace-if-exists semantics, use PutItem itself — PartiQL INSERT deliberately never replaces.
What it means
DuplicateItemException: There was an attempt to insert an item with the
same primary key as an item that already exists in the DynamoDB table.The PartiQL data-plane (ExecuteStatement / ExecuteTransaction / BatchExecuteStatement) maps INSERT to a conditional create — it succeeds only when no item with that primary key exists. That's the opposite default from the native PutItem, which silently replaces an existing item. If you came from SQL expecting INSERT to fail on a duplicate key, this is exactly that behavior; if you expected upsert semantics, this error is the surprise.
Why it happens
- The item genuinely already exists — a retry, a replay, or two writers racing on the same key both issuing
INSERT. - You wanted an update, not a create — porting
PutItem-style code to PartiQL and assumingINSERTreplaces. - A non-idempotent retry loop — the first attempt succeeded but the response was lost (timeout), and the retry re-inserts the same key.
- A synthetic key that isn't unique — the partition/sort key you compose collides more often than you think (e.g. a timestamp at second precision).
How to fix it
Updating an existing item? Use
UPDATE:UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'Want replace-if-exists (PutItem semantics)? Call
PutItem— PartiQL has no upsert statement, and the native API's default is exactly the overwrite you're after:await client.send(new PutItemCommand({TableName: 'orders', Item: item}));Treat it as success when the create is idempotent — if a retry hits
DuplicateItemExceptionfor an item your first attempt already wrote, catching and ignoring it is often the correct handling.Keep
INSERTwhen you rely on uniqueness — the exception is your create-only guard, the PartiQL equivalent ofattribute_not_exists()on aPutItemcondition.
Trying statements against real data is the quickest way to internalize the INSERT/UPDATE split — the DynoTable desktop app runs PartiQL in a SQL workbench against your live tables, and the DynamoDB Expression Builder emits the equivalent native-API requests when you need PutItem semantics instead.
Related errors
- ConditionalCheckFailedException — the native-API twin:
attribute_not_exists()guard failing onPutItem. - ValidationException: Unexpected from source — the other common PartiQL rejection.
- Learn: PartiQL examples · PartiQL vs SQL
References
- ExecuteStatement — Amazon DynamoDB API Reference (DuplicateItemException)
- PartiQL insert statements for DynamoDB — Developer Guide
- PartiQL update statements for DynamoDB — Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.