DuplicateItemException: プライマリキーの重複
TL;DR — PartiQL の INSERT は厳密な「作成」です。同じプライマリキーを持つアイテムがすでに存在する場合、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 を条件付きの作成にマップします — そのプライマリキーを持つアイテムが存在しない場合にのみ成功します。既存のアイテムを黙って置き換えるネイティブの PutItem とは、既定が正反対です。SQL から来て INSERT がキー重複で失敗することを期待していたなら、これはまさにその動作です。upsert のセマンティクスを期待していたなら、このエラーが驚きということになります。
発生する理由
- アイテムが本当にすでに存在する — リトライ、リプレイ、あるいは同じキーで競合する2つのライターが両方
INSERTを発行した。 - 作成ではなく更新がしたかった —
PutItem形式のコードを PartiQL に移植し、INSERTが置換すると思い込んだ。 - 冪等でないリトライループ — 最初の試行は成功したがレスポンスが失われ(タイムアウト)、リトライが同じキーを再挿入した。
- 一意でない合成キー — 組み立てたパーティション/ソートキーが、思っているより頻繁に衝突している(例: 秒精度のタイムスタンプ)。
修正方法
既存のアイテムを更新するなら
UPDATEを使います:UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'「存在すれば置換」(PutItem のセマンティクス)が欲しいなら
PutItemを呼びます — PartiQL に upsert 文はなく、ネイティブ API の既定こそがまさに求めている上書きです:await client.send(new PutItemCommand({TableName: 'orders', Item: item}));作成が冪等なら成功として扱います — 最初の試行がすでに書き込んだアイテムに対してリトライが
DuplicateItemExceptionに当たったのなら、キャッチして無視するのが正しい処理であることが多いです。一意性に頼っているなら
INSERTのままにします — この例外は作成専用のガードであり、PutItemの条件式におけるattribute_not_exists()の PartiQL 版です。
INSERT/UPDATE の使い分けを身につけるには、実データに対して文を試すのが一番の近道です — DynoTable の PartiQL エディタは、インラインの診断とクイックフィックス付きで、実際のテーブルに対して文を実行します。また DynamoDB Expression Builder は、PutItem のセマンティクスが必要なときに同等のネイティブ API リクエストを生成します。
再現方法
すでに存在するプライマリキーに対する PartiQL の INSERT です。
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'}`
})
);実際の出力:
DuplicateItem: Duplicate primary key exists in table
HTTP 400ローカルでテストするなら知っておく価値があります。DynamoDB Local はこれを上記の短いメッセージ付きの DuplicateItem として表面化させますが、サービスの API リファレンスはもっと長い一文を伴う DuplicateItemException として記載しています。正確な名前や文言ではなく、HTTP 400 と操作の組み合わせで照合してください。さもないとハンドラが Local と実テーブルとで違う振る舞いをします。
関連するエラー
- ConditionalCheckFailedException — ネイティブ API 側の双子:
PutItemでattribute_not_exists()ガードが失敗するケース。 - ValidationException: Unexpected from source — もう1つのよくある PartiQL の拒否。
- 学習: PartiQL の例 · PartiQL と SQL
参考資料
- ExecuteStatement — Amazon DynamoDB API Reference (DuplicateItemException)
- PartiQL insert statements for DynamoDB — Developer Guide
- PartiQL update statements for DynamoDB — Developer Guide
最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。
2026-07-26 に DynamoDB Local 2.x と AWS SDK for JavaScript v3.1095.0 で再現しました — 上記の出力はそのままの逐語です。