DynamoDB TransactionCanceledException — el código ConditionalCheckFailed

TL;DR — Tu TransactWriteItems fue cancelada y el array CancellationReasons contiene una entrada ConditionalCheckFailed. Una de las expresiones de condición de la transacción no se cumplió, así que DynamoDB revirtió todas las acciones de forma atómica. Lee el array de razones — sus entradas son posicionales, una por item solicitado — para encontrar qué condición de item falló, y luego arregla la precondición de ese item o los datos.

Qué significa

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 es todo-o-nada. Si el ConditionExpression de cualquier acción individual evalúa a false, DynamoDB cancela la petición entera y reporta una lista de razones por item. ConditionalCheckFailed en la posición i significa que la condición del i-ésimo item no se cumplió — la transacción nunca se aplicó parcialmente.

Por qué ocurre

  • Fallo de bloqueo optimista — una guarda version = :v / attribute_not_exists(pk) falló porque otro escritor ya cambió o creó el item.
  • Guarda de unicidad activada — un insert con attribute_not_exists(pk) perdió una carrera, así que el item ya existe.
  • Lectura obsoleta — la condición se construyó a partir de un valor que ha cambiado desde entonces.
  • Lista de razones mal leída — el array es posicional, ordenado como tus TransactItems; un None en una posición significa que ese item estaba bien, ConditionalCheckFailed marca el que falló. (Otros códigos del array — TransactionConflict, ItemCollectionSizeLimitExceeded, ProvisionedThroughputExceeded, ThrottlingError, ValidationError — significan algo distinto.)

Cómo solucionarlo

  1. Inspecciona CancellationReasons en la excepción y encuentra el índice con ConditionalCheckFailed — esa es la acción que falla.
  2. Vuelve a leer el item y decide: reintenta con una precondición fresca (bucle de reintento de bloqueo optimista) o expón un conflicto al llamante.
  3. Arregla la condición si es incorrecta — p. ej. attribute_not_exists(pk) sobre un item que legítimamente ya existe.
  4. Añade ReturnValuesOnConditionCheckFailure: ALL_OLD a la acción que falla para que DynamoDB devuelva el item que rompió la condición (genial para depurar).
  5. Acota tus reintentos — una condición que falla de forma persistente es un conflicto de negocio real, no un error transitorio; no reintentes eternamente.

¿Depurando una transacción fallida a mano? El área de preparación de DynoTable muestra el estado actual del item junto a tu cambio pendiente, para que veas exactamente por qué la precondición no se cumplió antes de reintentar.

FAQ

¿Cómo sé qué item de mi transacción falló? Lee el array CancellationReasons de la TransactionCanceledException. Es posicional — una entrada por item solicitado, en orden. La entrada con código ConditionalCheckFailed identifica la acción cuya expresión de condición evaluó a false; las entradas con código None tuvieron éxito.

¿Es reintentable un ConditionalCheckFailed dentro de una transacción? No automáticamente. Es un conflicto de precondición real, no un error transitorio. Vuelve a leer el item, decide si la escritura todavía aplica, y reintenta con una condición fresca — o expón el conflicto al usuario.

Errores relacionados

Referencias

Verificado por última vez el 2026-07-13 contra la documentación oficial de AWS enlazada arriba.

Trabaja con DynamoDB sin la Consola

Un cliente de escritorio rápido para DynamoDB que ejecuta el SQL real que DynamoDB no puede — JOINs, GROUP BY, agregaciones — con edición visual y un agente de IA con tus propias claves de Bedrock.

Prueba gratuita de 30 días, sin tarjeta — después, el plan Free sin límite de tiempo.