DynamoDB TransactionCanceledException
TL;DR — Uno (o más) Items de tu TransactWriteItems / TransactGetItems falló, así que DynamoDB revirtió la transacción entera. La causa real está en el array CancellationReasons — léelo; el Code de razón por Item te dice exactamente qué Item y por qué.
Qué significa
Las transacciones de DynamoDB son todo o nada. Si la condición de cualquier Item falla, se supera la capacidad, o dos transacciones colisionan, todo se cancela y no se escribe nada. El mensaje de nivel superior es genérico:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None, TransactionConflict]La lista entre corchetes es posicional — una entrada por Item de tu transacción, en orden. DynamoDB devuelve esta excepción con estado HTTP 400, y los SDK de AWS no la reintentan automáticamente — tu código decide, por código de razón, si un reintento tiene sentido.
Por qué ocurre (los códigos de razón)
ConditionalCheckFailed— elConditionExpressionde ese Item evaluó a falso (consulta ConditionalCheckFailedException).TransactionConflict— otra transacción concurrente (o escritura) está operando sobre el mismo Item; reintenta con backoff.ProvisionedThroughputExceeded— la tabla/índice del Item se quedó sin capacidad.ThrottlingError— la tabla o el índice (normalmente bajo demanda, mientras DynamoDB aún lo escala) limitó la escritura; reintenta con backoff.ValidationError— ese Item estaba mal formado (valores de parámetros inválidos, ruta de documento, tipo de operando, desbordamiento de tamaño, …).ItemCollectionSizeLimitExceeded— una colección de Items de un LSI alcanzó los 10 GB.None— ese Item estaba bien; el fallo estaba en otra parte de la lista.
Ese es el conjunto de códigos documentado completo. Ten en cuenta que una clave de Item duplicada (el mismo Item apuntado por dos acciones) no es un código de cancelación — DynamoDB rechaza esa petición de entrada como un ValidationException en su lugar.
Cómo solucionarlo
- Lee
CancellationReasonsdel error, no solo el mensaje. Mapea cada entrada de vuelta a tu Item de entrada por índice. - Ramifica por código:
ConditionalCheckFailed→ lógica de negocio;TransactionConflict/ThrottlingError/ProvisionedThroughputExceeded→ reintenta con backoff exponencial;ValidationError→ corrige la petición. - Evita las claves duplicadas — una sola transacción no puede tocar el mismo Item dos veces.
¿Editando Items a mano? El área de preparación de DynoTable agrupa tus ediciones en una sola escritura transaccional y te deja revisar cada Item antes de confirmar — la misma semántica de todo o nada sin construir la petición a mano.
Ejemplo
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
¿Por qué se canceló mi transacción de DynamoDB? Un Item del TransactWriteItems/TransactGetItems falló — una comprobación de condición, un límite de rendimiento/limitación, o un conflicto con otra transacción concurrente — así que DynamoDB revirtió toda la transacción y no escribió nada. La razón por Item está en el array CancellationReasons.
¿Cómo encuentro qué Item de la transacción falló? Lee el array CancellationReasons del TransactionCanceledException. Tiene una entrada por Item de entrada, en el mismo orden; la entrada cuyo Code no es "None" es el Item que causó la cancelación.
Reproducirlo
Dos escrituras en una transacción, la segunda protegida por una condición que no puede cumplirse. La transacción entera se revierte, y los veredictos por acción llegan en CancellationReasons, alineados posicionalmente con TransactItems:
await client.send(
new TransactWriteItemsCommand({
TransactItems: [
{Put: {TableName: 'orders', Item: {pk: {S: 'OK'}, sk: {S: 'META'}}}},
{
Put: {
TableName: 'orders',
Item: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}},
ConditionExpression: 'attribute_not_exists(pk)' // ORDER#1 already exists
}
}
]
})
);Salida real:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [None, ConditionalCheckFailed]
HTTP 400
error.CancellationReasons:
[
{
"Code": "None"
},
{
"Code": "ConditionalCheckFailed",
"Message": "The conditional request failed"
}
]La primera acción informa None — no falló, se revirtió porque falló su vecina. Solo la entrada cuyo Code no es None identifica al culpable real, y su índice es el índice de la acción problemática en tu propio array TransactItems.
Errores relacionados
- ConditionalCheckFailedException
- ProvisionedThroughputExceededException
- Ejemplo de código: TransactWriteItems in Node.js · en Python (boto3) — una transacción ejecutable con la que comparar.
- Aprende: DynamoDB transactions
Referencias
- TransactWriteItems — Amazon DynamoDB API Reference
- TransactGetItems — Amazon DynamoDB API Reference
- Amazon DynamoDB Transactions: How it works — Amazon DynamoDB Developer Guide
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
Verificado por última vez el 2026-07-13 contra la documentación oficial de AWS enlazada arriba.
Reproducido el 2026-07-26 contra DynamoDB Local 2.x con AWS SDK for JavaScript v3.1095.0 — la salida de arriba es literal.