DuplicateItemException: duplicate primary key

TL;DR — Ein PartiQL INSERT ist ein striktes Create: Wenn ein Item mit demselben Primärschlüssel bereits existiert, wirft DynamoDB DuplicateItemException, statt es zu überschreiben. Um das bestehende Item zu ändern, nutze PartiQL UPDATE; um PutItems Replace-if-exists-Semantik zu bekommen, nutze PutItem selbst — PartiQL INSERT ersetzt bewusst nie.

Was es bedeutet

DuplicateItemException: There was an attempt to insert an item with the
same primary key as an item that already exists in the DynamoDB table.

Die PartiQL-Data-Plane (ExecuteStatement / ExecuteTransaction / BatchExecuteStatement) bildet INSERT auf ein bedingtes Create ab — es gelingt nur, wenn kein Item mit diesem Primärschlüssel existiert. Das ist der entgegengesetzte Default zum nativen PutItem, das ein bestehendes Item stillschweigend ersetzt. Wenn du von SQL kommst und erwartest, dass INSERT bei einem doppelten Key fehlschlägt, ist das genau dieses Verhalten; wenn du Upsert-Semantik erwartet hast, ist dieser Fehler die Überraschung.

Warum es passiert

  • Das Item existiert tatsächlich bereits — ein Retry, ein Replay oder zwei Writer, die auf demselben Key um die Wette laufen und beide INSERT absetzen.
  • Du wolltest ein Update, kein CreatePutItem-artigen Code auf PartiQL portiert und angenommen, dass INSERT ersetzt.
  • Eine nicht-idempotente Retry-Schleife — der erste Versuch gelang, aber die Antwort ging verloren (Timeout), und der Retry fügt denselben Key erneut ein.
  • Ein synthetischer Key, der nicht eindeutig ist — der zusammengesetzte Partition-/Sort-Key kollidiert öfter, als du denkst (z. B. ein Zeitstempel mit Sekundengenauigkeit).

So behebst du es

  1. Ein bestehendes Item aktualisieren? Nutze UPDATE:

    UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'
  2. Replace-if-exists gewünscht (PutItem-Semantik)? Rufe PutItem auf — PartiQL hat kein Upsert-Statement, und der Default der nativen API ist genau das Überschreiben, das du willst:

    await client.send(new PutItemCommand({TableName: 'orders', Item: item}));
  3. Behandle es als Erfolg, wenn das Create idempotent ist — wenn ein Retry auf DuplicateItemException für ein Item trifft, das dein erster Versuch bereits geschrieben hat, ist Abfangen und Ignorieren oft die korrekte Behandlung.

  4. Behalte INSERT, wenn du dich auf Eindeutigkeit verlässt — die Exception ist dein Create-only-Guard, das PartiQL-Äquivalent zu attribute_not_exists() auf einer PutItem-Bedingung.

Statements gegen echte Daten auszuprobieren ist der schnellste Weg, die INSERT/UPDATE-Aufteilung zu verinnerlichen — DynoTables PartiQL-Editor führt Statements mit Inline-Diagnosen und Quick-Fixes gegen deine Live-Tabellen aus, und der DynamoDB Expression Builder gibt die äquivalenten nativen API-Anfragen aus, wenn du stattdessen PutItem-Semantik brauchst.

So reproduzierst du es

Ein PartiQL INSERT für einen Primärschlüssel, der bereits existiert:

await client.send(
  new PutItemCommand({
    TableName: 'orders',
    Item: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}}
  })
);
await client.send(
  new ExecuteStatementCommand({
    Statement: `INSERT INTO "orders" VALUE {'pk':'ORDER#1','sk':'META'}`
  })
);

Echte Ausgabe:

DuplicateItem: Duplicate primary key exists in table
HTTP 400

Wissenswert, wenn du lokal testest: DynamoDB Local zeigt das als DuplicateItem mit der kurzen Meldung oben, während die Service-API-Referenz es als DuplicateItemException mit einem längeren Satz dokumentiert. Gleiche auf HTTP 400 plus die Operation ab, nicht auf den exakten Namen oder Wortlaut, sonst verhält sich dein Handler gegen Local anders als gegen die echte Tabelle.

Verwandte Fehler

Referenzen

Zuletzt verifiziert am 2026-07-13 gegen die oben verlinkte offizielle AWS-Dokumentation.

Am 2026-07-26 gegen DynamoDB Local 2.x mit dem AWS SDK for JavaScript v3.1095.0 reproduziert — die Ausgabe oben ist wortgetreu.

Mit DynamoDB ohne die Console arbeiten

Ein schneller DynamoDB-Desktop-Client, der das echte SQL ausführt, das DynamoDB nicht kann — JOINs, GROUP BY, Aggregationen — mit visueller Bearbeitung und einem KI-Agenten auf deinen eigenen Bedrock-Schlüsseln.

30 Tage kostenlos testen, keine Kreditkarte — danach der Kostenlos-Tarif ohne Zeitlimit.