DuplicateItemException: duplicate primary key

TL;DR — PartiQL INSERT 是嚴格的建立:若已存在相同 primary key 的項目,DynamoDB 會拋出 DuplicateItemException 而非覆寫它。要修改既有項目請用 PartiQL UPDATE;要取得 PutItem 的「存在即替換」語義,請用 PutItem 本身 — PartiQL INSERT 刻意永不替換。

這是什麼意思

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

PartiQL 資料平面(ExecuteStatement / ExecuteTransaction / BatchExecuteStatement)將 INSERT 對應為條件式建立 — 只有在不存在該 primary key 的項目時才成功。這與原生 PutItem 的預設相反,後者會默默替換既有項目。若你來自 SQL 且預期 INSERT 在重複鍵時失敗,這正是那種行為;若你預期 upsert 語義,這個錯誤就是意外。

為什麼會發生

  • 項目確實已經存在 — 重試、重播,或兩個寫入者在同一個鍵上競爭而都發出 INSERT
  • 你想要的是更新,而非建立 — 將 PutItem 風格的程式碼移植到 PartiQL 並假設 INSERT 會替換。
  • 非冪等的重試迴圈 — 第一次嘗試成功但回應遺失(逾時),而重試重新插入了相同的鍵。
  • 不唯一的合成鍵 — 你組合的 partition/sort key 比你想的更常碰撞(例如以秒為精度的時間戳)。

如何修正

  1. 要更新既有項目?用 UPDATE

    UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'
  2. 想要存在即替換(PutItem 語義)?呼叫 PutItem — PartiQL 沒有 upsert 語句,而原生 API 的預設正是你想要的覆寫:

    await client.send(new PutItemCommand({TableName: 'orders', Item: item}));
  3. 當建立是冪等時將它視為成功 — 若重試對一個你第一次嘗試已寫入的項目碰到 DuplicateItemException,捕捉並忽略它往往是正確的處理方式。

  4. 當你依賴唯一性時保留 INSERT — 這個例外就是你的僅建立防護,等同於 PutItem 條件上的 attribute_not_exists()

對真實資料嘗試語句是內化 INSERT/UPDATE 之別最快的方式 — DynoTable 桌面應用程式在 SQL workbench 中對你的即時表格執行 PartiQL,而當你需要 PutItem 語義時,DynamoDB Expression Builder 會產出等效的原生 API 請求。

相關錯誤

References

最後驗證於 2026-07-13,對照上方連結的 AWS 官方文件。

不必透過主控台就能操作 DynamoDB

DynoTable 是一款快速的 DynamoDB 桌面用戶端 — 瀏覽表格、執行 SQL 風格的查詢,並在本機編輯項目。