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 が置換すると思い込んだ。
  • 冪等でないリトライループ — 最初の試行は成功したがレスポンスが失われ(タイムアウト)、リトライが同じキーを再挿入した。
  • 一意でない合成キー — 組み立てたパーティション/ソートキーが、思っているより頻繁に衝突している(例: 秒精度のタイムスタンプ)。

修正方法

  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() の 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 と実テーブルとで違う振る舞いをします。

関連するエラー

参考資料

最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

2026-07-26 に DynamoDB Local 2.x と AWS SDK for JavaScript v3.1095.0 で再現しました — 上記の出力はそのままの逐語です。

Console なしで DynamoDB を扱う

DynamoDB では実行できない本物の SQL(JOINs、GROUP BY、集計)を実行する高速な DynamoDB デスクトップクライアント。ビジュアル編集と、あなた自身の Bedrock キーで動く AI エージェントを備えています。

30日間無料トライアル、クレジットカード不要 — その後は期限のない Free プラン。