DynamoDB TransactionCanceledException — ConditionalCheckFailed

TL;DR — Your TransactWriteItems was canceled and the CancellationReasons array holds a ConditionalCheckFailed entry. One of the transaction's condition expressions didn't hold, so DynamoDB rolled back every action atomically. Read the reasons array — its entries are positional, one per requested item — to find which item's condition failed, then fix that item's precondition or the data.

What it means

TransactionCanceledException: Transaction cancelled, please refer cancellation
reasons for specific reasons [ConditionalCheckFailed, None, None]
# CancellationReasons[0] = { Code: "ConditionalCheckFailed",
#                            Message: "The conditional request failed" }

# what the engine actually returns, reproduced against DynamoDB Local:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed]

TransactWriteItems is all-or-nothing. If any single action's ConditionExpression evaluates false, DynamoDB cancels the whole request and reports a per-item reason list. ConditionalCheckFailed at position i means the i-th item's condition wasn't met — the transaction never partially applied.

Why it happens

  • Optimistic-lock miss — a version = :v / attribute_not_exists(pk) guard failed because another writer already changed or created the item.
  • Uniqueness guard tripped — an attribute_not_exists(pk) insert lost a race, so the item already exists.
  • Stale read — the condition was built from a value that has since changed.
  • Reason list misread — the array is positional, ordered like your TransactItems; a None at a slot means that item was fine, ConditionalCheckFailed marks the one that failed. (Other codes in the array — TransactionConflict, ItemCollectionSizeLimitExceeded, ProvisionedThroughputExceeded, ThrottlingError, ValidationError — mean something different.)

How to fix it

  1. Inspect CancellationReasons in the exception and find the index with ConditionalCheckFailed — that's the failing action.
  2. Re-read the item and decide: retry with a fresh precondition (optimistic-lock retry loop) or surface a conflict to the caller.
  3. Fix the condition if it's wrong — e.g. attribute_not_exists(pk) on an item that legitimately already exists.
  4. Add ReturnValuesOnConditionCheckFailure: ALL_OLD to the failing action so DynamoDB returns the item that broke the condition (great for debugging).
  5. Bound your retries — a persistently failing condition is a real business conflict, not a transient error; don't retry forever.

Debugging a failed transaction by hand? DynoTable's staging area shows the current item state next to your pending change, so you can see exactly why the precondition didn't hold before you retry.

FAQ

How do I know which item in my transaction failed? Read the CancellationReasons array on the TransactionCanceledException. It's positional — one entry per requested item, in order. The entry with code ConditionalCheckFailed identifies the action whose condition expression evaluated false; entries with code None succeeded.

Is a ConditionalCheckFailed inside a transaction retryable? Not automatically. It's a real precondition conflict, not a transient error. Re-read the item, decide whether the write still applies, and retry with a fresh condition — or surface the conflict to the user.

References

Last verified 2026-07-13 against the official AWS documentation linked above.

Work with DynamoDB without the Console

A fast DynamoDB desktop client that runs the real SQL DynamoDB can’t — JOINs, GROUP BY, aggregates — with visual editing and an AI agent on your own Bedrock keys.

Free 30-day trial, no credit card — then the Free plan with no time limit.