DynamoDB ConditionalCheckFailedException

TL;DR — Dein Write trug ein ConditionExpression, das gegen das aktuelle Item zu false ausgewertet wurde, also hat DynamoDB den Write abgewiesen und das Item unberührt gelassen. Das ist meist erwartet (Optimistic Concurrency, „create if not exists") — fange es ab und verzweige, wiederhole nicht blind.

Was es bedeutet

Anders als bei einer ValidationException war die Anfrage wohlgeformt. DynamoDB hat deine Bedingung ausgewertet, und sie hielt nicht, also wurde das PutItem / UpdateItem / DeleteItem (oder ein einzelnes Item innerhalb eines TransactWriteItems) verweigert. Keine Daten haben sich geändert. Es gibt HTTP 400 zurück und ist so nicht wiederholbar.

Warum es passiert

  • attribute_not_exists(pk)-Guard bei einem Create — das Item existiert bereits (ein doppelter Insert).
  • attribute_exists(pk)-Guard bei einem Update/Delete — das Item ist weg.
  • Optimistic Concurrency — ein version = :expected (oder updatedAt) Check, bei dem ein anderer Writer zuerst dort war.
  • Business-Rule-Guardsbalance >= :amount, #status = :expected, die nicht mehr zum gespeicherten Item passen.

So behebst du es

  1. Behandle es als normales Ergebnis, nicht als Fehler. Fange die Exception ab und entscheide, was eine fehlgeschlagene Bedingung in deinem Ablauf bedeutet (Item existiert bereits → gib es zurück; Version veraltet → neu lesen und mit der neuen Version wiederholen).
  2. Lies das aktuelle Item zurück. Setze ReturnValuesOnConditionCheckFailure: 'ALL_OLD', um das Item zu erhalten, das den Fehler verursacht hat, ohne einen zweiten Roundtrip — es kommt auf der Exception selbst zurück (dem Item-Feld), und es wird keine Read-Kapazität verbraucht.
  3. Neu lesen + neu berechnen für Concurrency, dann mit der frischen Version erneut versuchen — sende nicht einfach denselben erwarteten Wert erneut.

Genau diese Neu-lesen-und-vergleichen-Schleife übernimmt DynoTables Staging-Bereich für manuelle Änderungen — er staged deine Writes und zeigt dir bei einem Optimistic-Locking-Konflikt das aktuelle Item neben deiner Änderung, sodass du den Konflikt auflösen kannst, bevor irgendetwas gesendet wird.

Beispiel

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

Was verursacht eine ConditionalCheckFailedException in DynamoDB? Ein Write (PutItem, UpdateItem, DeleteItem oder ein TransactWrite-Item) trug ein ConditionExpression, das gegen das aktuelle Item zu false ausgewertet wurde — zum Beispiel attribute_not_exists(pk) auf einem Key, der bereits existiert, oder ein Versionscheck, der nicht mehr passt. DynamoDB weist den Write ab und lässt das Item unverändert.

Wie verhindere ich, dass eine ConditionalCheckFailedException meine App zum Absturz bringt? Fange die Exception ab und behandle sie als erwartetes Ergebnis, nicht als Fehler. Eine fehlgeschlagene Bedingung bedeutet meist „jemand anderes war zuerst da" (Optimistic Concurrency) oder „das Item existiert bereits" — verzweige darauf, statt blind zu wiederholen.

So reproduzierst du es

Ein PutItem, abgesichert durch attribute_not_exists, gegen einen Key, der sehr wohl existiert:

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

Echte Ausgabe:

ConditionalCheckFailedException: The conditional request failed
HTTP 400

Die Meldung ist bewusst nichtssagend — sie sagt nie, welcher Teil der Bedingung fehlschlug oder was das Item tatsächlich enthielt. Übergib ReturnValuesOnConditionCheckFailure: "ALL_OLD", und das aktuelle Item kommt auf error.Item zurück, was aus einer Vermutung ein Diff macht.

Verwandte Fehler

Referenzen

Zuletzt verifiziert am 2026-07-13 gegen die oben verlinkte offizielle AWS-Dokumentation.

Am 2026-07-26 gegen DynamoDB Local 2.x mit dem AWS SDK for JavaScript v3.1095.0 reproduziert — die Ausgabe oben ist wortgetreu.

Mit DynamoDB ohne die Console arbeiten

Ein schneller DynamoDB-Desktop-Client, der das echte SQL ausführt, das DynamoDB nicht kann — JOINs, GROUP BY, Aggregationen — mit visueller Bearbeitung und einem KI-Agenten auf deinen eigenen Bedrock-Schlüsseln.

30 Tage kostenlos testen, keine Kreditkarte — danach der Kostenlos-Tarif ohne Zeitlimit.