DuplicateItemException: duplicate primary key
TL;DR — Um INSERT do PartiQL é uma criação estrita: se um item com a mesma chave primária já existe, o DynamoDB lança DuplicateItemException em vez de sobrescrevê-lo. Para modificar o item existente use o UPDATE do PartiQL; para obter a semântica de substituir-se-existir do PutItem, use o próprio PutItem — o INSERT do PartiQL deliberadamente nunca substitui.
O que significa
DuplicateItemException: There was an attempt to insert an item with the
same primary key as an item that already exists in the DynamoDB table.O data-plane do PartiQL (ExecuteStatement / ExecuteTransaction / BatchExecuteStatement) mapeia INSERT para uma criação condicional — ele só é bem-sucedido quando nenhum item com aquela chave primária existe. Esse é o padrão oposto do PutItem nativo, que substitui um item existente silenciosamente. Se você veio do SQL esperando que INSERT falhe em uma chave duplicada, este é exatamente esse comportamento; se você esperava semântica de upsert, este erro é a surpresa.
Por que isso acontece
- O item genuinamente já existe — um retry, um replay, ou dois processos de escrita competindo na mesma chave ambos emitindo
INSERT. - Você queria uma atualização, não uma criação — portar código no estilo
PutItempara o PartiQL e supor queINSERTsubstitui. - Um loop de retry não idempotente — a primeira tentativa foi bem-sucedida mas a resposta foi perdida (timeout), e o retry reinsere a mesma chave.
- Uma chave sintética que não é única — a chave de partição/ordenação que você compõe colide mais frequentemente do que você imagina (por exemplo, um timestamp com precisão de segundos).
Como corrigir
Atualizando um item existente? Use
UPDATE:UPDATE "orders" SET status = 'shipped' WHERE pk = 'ORDER#123' AND sk = 'META'Quer substituir-se-existir (semântica do PutItem)? Chame
PutItem— o PartiQL não tem instrução de upsert, e o padrão da API nativa é exatamente a sobrescrita que você busca:await client.send(new PutItemCommand({TableName: 'orders', Item: item}));Trate como sucesso quando a criação é idempotente — se um retry encontra
DuplicateItemExceptionpara um item que sua primeira tentativa já escreveu, capturá-lo e ignorá-lo é frequentemente o tratamento correto.Mantenha o
INSERTquando você depende da unicidade — a exceção é seu guard de somente-criação, o equivalente no PartiQL deattribute_not_exists()em uma condição dePutItem.
Testar instruções contra dados reais é a forma mais rápida de internalizar a divisão INSERT/UPDATE — o editor PartiQL do DynoTable roda instruções contra suas tabelas ao vivo com diagnósticos inline e correções rápidas, e o DynamoDB Expression Builder emite as requisições equivalentes da API nativa quando você precisa da semântica de PutItem em vez disso.
Reproduza
Um INSERT do PartiQL para uma chave primária que já existe:
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'}`
})
);Saída real:
DuplicateItem: Duplicate primary key exists in table
HTTP 400Vale saber se você testa localmente: o DynamoDB Local expõe isso como DuplicateItem com a mensagem curta acima, enquanto a referência da API do serviço documenta como DuplicateItemException com uma frase mais longa. Case pelo HTTP 400 mais a operação, não pelo nome ou pelo texto exatos, senão seu handler vai se comportar de um jeito contra o Local e de outro contra a tabela real.
Erros relacionados
- ConditionalCheckFailedException — o gêmeo da API nativa: guard
attribute_not_exists()falhando em umPutItem. - ValidationException: Unexpected from source — a outra rejeição comum do PartiQL.
- Aprenda: PartiQL examples · PartiQL vs SQL
Referências
- ExecuteStatement — Amazon DynamoDB API Reference (DuplicateItemException)
- PartiQL insert statements for DynamoDB — Developer Guide
- PartiQL update statements for DynamoDB — Developer Guide
Verificado pela última vez em 2026-07-13 contra a documentação oficial da AWS vinculada acima.
Reproduzido em 2026-07-26 no DynamoDB Local 2.x com o AWS SDK for JavaScript v3.1095.0 — a saída acima é literal.