DynamoDB ConditionalCheckFailedException

TL;DR — Sua escrita carregava uma ConditionExpression que avaliou como false contra o item atual, então o DynamoDB rejeitou a escrita e deixou o item intocado. Isso normalmente é esperado (concorrência otimista, "criar se não existir") — capture-o e ramifique, não tente novamente às cegas.

O que significa

Ao contrário de um ValidationException, a requisição estava bem formada. O DynamoDB avaliou sua condição e ela não se sustentou, então o PutItem / UpdateItem / DeleteItem (ou um único item dentro de um TransactWriteItems) foi recusado. Nenhum dado mudou. Ele retorna HTTP 400 e não é retentável como está.

Por que isso acontece

  • Guard attribute_not_exists(pk) em uma criação — o item já existe (uma inserção duplicada).
  • Guard attribute_exists(pk) em uma atualização/exclusão — o item desapareceu.
  • Concorrência otimista — uma verificação version = :expected (ou updatedAt) onde outro processo de escrita chegou primeiro.
  • Guards de regra de negóciobalance >= :amount, #status = :expected que não correspondem mais ao item armazenado.

Como corrigir

  1. Trate-o como um resultado normal, não uma falha. Capture a exceção e decida o que uma condição falha significa no seu fluxo (item já existe → retorne-o; versão desatualizada → releia e tente novamente com a nova versão).
  2. Releia o item atual. Defina ReturnValuesOnConditionCheckFailure: 'ALL_OLD' para obter o item que causou a falha sem um segundo round-trip — ele volta na própria exceção (o campo Item), e nenhuma capacidade de leitura é consumida.
  3. Releia + recalcule para concorrência, depois tente novamente com a versão fresca — não apenas reenvie o mesmo valor esperado.

Esse laço de reler-e-comparar é exatamente o que a área de preparação do DynoTable faz para edições manuais — ela prepara suas escritas e, em um conflito de bloqueio otimista, mostra o item atual ao lado da sua alteração para você resolver tudo antes de qualquer coisa ser enviada.

Exemplo

import {DynamoDBClient} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocumentClient, PutCommand} from '@aws-sdk/lib-dynamodb';
import {ConditionalCheckFailedException} from '@aws-sdk/client-dynamodb';

const doc = DynamoDBDocumentClient.from(new DynamoDBClient({}));

try {
  await doc.send(
    new PutCommand({
      TableName: 'Users',
      Item: {pk: 'USER#1', email: 'a@b.com'},
      ConditionExpression: 'attribute_not_exists(pk)' // create-only
    })
  );
} catch (err) {
  if (err instanceof ConditionalCheckFailedException) {
    // Expected: the user already exists. Handle gracefully.
    return {alreadyExists: true};
  }
  throw err;
}

FAQ

O que causa um ConditionalCheckFailedException no DynamoDB? Uma escrita (PutItem, UpdateItem, DeleteItem ou um item de TransactWrite) carregou uma ConditionExpression que avaliou como falso contra o item atual — por exemplo attribute_not_exists(pk) em uma chave que já existe, ou uma verificação de versão que não corresponde mais. O DynamoDB rejeita a escrita e deixa o item inalterado.

Como impeço que um ConditionalCheckFailedException derrube meu app? Capture a exceção e trate-a como um resultado esperado, não uma falha. Uma condição falha normalmente significa "alguém chegou primeiro" (concorrência otimista) ou "o item já existe" — ramifique com base nisso em vez de tentar novamente às cegas.

Reproduza

Um PutItem protegido por attribute_not_exists contra uma chave que existe:

await client.send(
  new PutItemCommand({
    TableName: 'orders',
    Item: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}},
    ConditionExpression: 'attribute_not_exists(pk)'
  })
);

Saída real:

ConditionalCheckFailedException: The conditional request failed
HTTP 400

A mensagem é deliberadamente pouco informativa — ela nunca diz qual parte da condição falhou, nem o que o item de fato continha. Passe ReturnValuesOnConditionCheckFailure: "ALL_OLD" e o item atual volta em error.Item, o que transforma isso de um palpite em um diff.

Erros relacionados

Referências

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.

Trabalhe com o DynamoDB sem o Console

Um cliente desktop rápido para DynamoDB que roda o SQL de verdade que o DynamoDB não consegue — JOINs, GROUP BY, agregações — com edição visual e um agente de IA com suas próprias chaves do Bedrock.

Teste grátis de 30 dias, sem cartão de crédito — depois o plano Grátis sem limite de tempo.