DynamoDB ConditionalCheckFailedException
TL;DR — Your write carried a ConditionExpression that evaluated to false against the current item, so DynamoDB rejected the write and left the item untouched. This is usually expected (optimistic concurrency, "create if not exists") — catch it and branch, don't retry blindly.
What it means
Unlike a ValidationException, the request was well-formed. DynamoDB evaluated your condition and it didn't hold, so the PutItem / UpdateItem / DeleteItem (or a single item inside a TransactWriteItems) was refused. No data changed. It returns HTTP 400 and is not retryable as-is.
Why it happens
attribute_not_exists(pk)guard on a create — the item already exists (a duplicate insert).attribute_exists(pk)guard on an update/delete — the item is gone.- Optimistic concurrency — a
version = :expected(orupdatedAt) check where another writer got there first. - Business-rule guards —
balance >= :amount,#status = :expectedthat no longer match the stored item.
How to fix it
- Treat it as a normal outcome, not a fault. Catch the exception and decide what a failed condition means in your flow (item already exists → return it; version stale → re-read and retry with the new version).
- Read the current item back. Set
ReturnValuesOnConditionCheckFailure: 'ALL_OLD'to get the item that caused the failure without a second round-trip. - Re-read + recompute for concurrency, then re-attempt with the fresh version — don't just resend the same expected value.
Example
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
What causes a ConditionalCheckFailedException in DynamoDB? A write (PutItem, UpdateItem, DeleteItem or a TransactWrite item) carried a ConditionExpression that evaluated to false against the current item — for example attribute_not_exists(pk) on a key that already exists, or a version check that no longer matches. DynamoDB rejects the write and leaves the item unchanged.
How do I stop a ConditionalCheckFailedException from crashing my app? Catch the exception and treat it as an expected outcome, not a fault. A failed condition usually means "someone else got there first" (optimistic concurrency) or "the item already exists" — branch on it instead of retrying blindly.
Related errors
- TransactionCanceledException — a failed condition inside a transaction.
- ValidationException (overview)
- Learn: Condition expressions · Atomic counters