DynamoDB TransactionCanceledException — 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" }

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? Inspecciona el estado actual del item en la aplicación de escritorio DynoTable para ver 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

DynoTable es un cliente de escritorio rápido para DynamoDB: explora tablas, ejecuta consultas estilo SQL y edita Items localmente.