DynamoDB ConditionalCheckFailedException

In breve — La tua scrittura portava un ConditionExpression che è risultato false rispetto all'Item attuale, quindi DynamoDB ha rifiutato la scrittura e ha lasciato l'Item intatto. Di solito è previsto (concorrenza ottimistica, "crea se non esiste") — intercettalo e ramifica, non riprovare alla cieca.

Cosa significa

A differenza di una ValidationException, la richiesta era ben formata. DynamoDB ha valutato la tua condizione e non era soddisfatta, quindi il PutItem / UpdateItem / DeleteItem (o un singolo Item all'interno di un TransactWriteItems) è stato rifiutato. Nessun dato è cambiato. Restituisce HTTP 400 e non è ripetibile così com'è.

Perché succede

  • Guard attribute_not_exists(pk) su una creazione — l'Item esiste già (un inserimento duplicato).
  • Guard attribute_exists(pk) su un aggiornamento/eliminazione — l'Item non c'è più.
  • Concorrenza ottimistica — un controllo version = :expected (o updatedAt) in cui un altro writer è arrivato prima.
  • Guard di regole di businessbalance >= :amount, #status = :expected che non corrispondono più all'Item memorizzato.

Come risolverlo

  1. Trattalo come un esito normale, non come un guasto. Intercetta l'eccezione e decidi cosa significa una condizione fallita nel tuo flusso (l'Item esiste già → restituiscilo; versione obsoleta → rileggi e riprova con la nuova versione).
  2. Rileggi l'Item attuale. Imposta ReturnValuesOnConditionCheckFailure: 'ALL_OLD' per ottenere l'Item che ha causato il fallimento senza un secondo round-trip — arriva sull'eccezione stessa (il campo Item), e non viene consumata capacità di lettura.
  3. Rileggi + ricalcola per la concorrenza, poi ritenta con la versione aggiornata — non reinviare semplicemente lo stesso valore atteso.

Questo loop di rilettura-e-confronto è esattamente ciò che l'area di staging di DynoTable fa per le modifiche manuali — mette in staging le tue scritture e, in caso di conflitto di concorrenza ottimistica, ti mostra l'Item attuale accanto alla tua modifica così puoi risolverlo prima che qualcosa venga inviato.

Esempio

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

Cosa causa una ConditionalCheckFailedException in DynamoDB? Una scrittura (PutItem, UpdateItem, DeleteItem o un Item di TransactWrite) portava un ConditionExpression risultato falso rispetto all'Item attuale — per esempio attribute_not_exists(pk) su una chiave che esiste già, o un controllo di versione che non corrisponde più. DynamoDB rifiuta la scrittura e lascia l'Item invariato.

Come impedisco a una ConditionalCheckFailedException di far crashare la mia applicazione? Intercetta l'eccezione e trattala come un esito previsto, non come un guasto. Una condizione fallita di solito significa "qualcun altro è arrivato prima" (concorrenza ottimistica) o "l'Item esiste già" — ramifica su di essa invece di riprovare alla cieca.

Riproducilo

Un PutItem protetto da attribute_not_exists contro una chiave che invece esiste:

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

Output reale:

ConditionalCheckFailedException: The conditional request failed
HTTP 400

Il messaggio è volutamente poco informativo — non dice mai quale parte della condizione è fallita, né cosa contenesse davvero l'Item. Passa ReturnValuesOnConditionCheckFailure: "ALL_OLD" e l'Item attuale torna in error.Item, il che trasforma tutto questo da una supposizione a un diff.

Errori correlati

Riferimenti

Ultima verifica 2026-07-13 rispetto alla documentazione ufficiale AWS collegata sopra.

Riprodotto il 2026-07-26 su DynamoDB Local 2.x con AWS SDK for JavaScript v3.1095.0 — l'output qui sopra è riportato alla lettera.

Lavora con DynamoDB senza la Console

Un client desktop veloce per DynamoDB che esegue il vero SQL che DynamoDB non può — JOINs, GROUP BY, aggregazioni — con modifica visuale e un agente AI sulle tue chiavi Bedrock.

Prova gratuita di 30 giorni, senza carta di credito — poi il piano Free senza limiti di tempo.