DynamoDB TransactionCanceledException
TL;DR — One (or more) items in your TransactWriteItems / TransactGetItems failed, so DynamoDB rolled back the entire transaction. The real cause is in the CancellationReasons array — read it; the reason Code per item tells you exactly which item and why.
What it means
DynamoDB transactions are all-or-nothing. If any item's condition fails, capacity is exceeded, or two transactions collide, the whole thing is cancelled and nothing is written. The top-level message is generic:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None, TransactionConflict]The bracketed list is positional — one entry per item in your transaction, in order.
Why it happens (the reason codes)
ConditionalCheckFailed— that item'sConditionExpressionevaluated to false (see ConditionalCheckFailedException).TransactionConflict— another concurrent transaction (or write) is operating on the same item; retry with backoff.ProvisionedThroughputExceeded— the item's table/index ran out of capacity.ThrottlingError— request-rate throttle; retry with backoff.ValidationError— that item was malformed.ItemCollectionSizeLimitExceeded— an LSI item collection hit 10 GB.None— that item was fine; the failure was elsewhere in the list.DuplicateItem— the same item key appears twice in one transaction (not allowed).
How to fix it
- Read
CancellationReasonsoff the error, not just the message. Map each entry back to your input item by index. - Branch by code:
ConditionalCheckFailed→ business logic;TransactionConflict/ThrottlingError/ProvisionedThroughputExceeded→ retry with exponential backoff;ValidationError→ fix the request. - Avoid duplicate keys — a single transaction can't touch the same item twice.
Example
import {DynamoDBClient, TransactionCanceledException} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocumentClient, TransactWriteCommand} from '@aws-sdk/lib-dynamodb';
const doc = DynamoDBDocumentClient.from(new DynamoDBClient({}));
try {
await doc.send(new TransactWriteCommand({TransactItems: [/* ... */]}));
} catch (err) {
if (err instanceof TransactionCanceledException) {
for (const [i, reason] of (err.CancellationReasons ?? []).entries()) {
if (reason.Code && reason.Code !== 'None') {
console.error(`item ${i} cancelled: ${reason.Code} — ${reason.Message}`);
}
}
}
throw err;
}FAQ
Why did my DynamoDB transaction get cancelled? One item in the TransactWriteItems/TransactGetItems failed — a condition check, a throughput/throttling limit, or a conflict with another concurrent transaction — so DynamoDB rolled the whole transaction back and wrote nothing. The per-item reason is in the CancellationReasons array.
How do I find which item in the transaction failed? Read the CancellationReasons array on the TransactionCanceledException. It has one entry per input item, in the same order; the entry whose Code is not "None" is the item that caused the cancellation.