How to fix TransactionConflictException: Operation failed due to a conflict with another request in DynamoDB
DynamoDB raises this error when your transaction or item-level write collides with another request touching the same key, so it rejects the new operation to keep the data consistent.
Quick fix
Fixes TransactionConflictException: Operation failed due to a conflict with another request
- Inspect CloudWatch metrics and cancellation details for the conflicting keys
- Retry with exponential backoff and jitter instead of immediate replays
- Reduce the transactional footprint and limit overlapping writes
- Serialize high-contention updates with optimistic locking or a version attribute
# TransactionConflictException: Operation failed due to a conflict with another reTransactionConflictException: Operation failed due to a conflict with another request
What this error means
The TransactionConflictException is DynamoDB telling you that it could not obtain a lock on your primary key because another request already held it. Serializable isolation around transactions means that once one operation begins mutating an item, other operations that reference that same item—whether they are TransactWriteItems / TransactGetItems or even non-transactional PutItem, UpdateItem, or DeleteItem calls—will be rejected with this message instead of allowing both to proceed. The "Operation failed due to a conflict with another request" text is the service tracing which request claimed the partition first and why the new call cannot commit.
Typical symptoms
- API calls return HTTP 400 with "TransactionConflictException: Operation failed due to a conflict with another request"
- TransactWriteItems responses surface TransactionCanceledException while the CancellationReasons list contains a Code of TransactionConflict
- CloudWatch TransactionConflict metric spikes for the table right when the error occurs
- Retries succeed only after the competing request finishes, so the error disappears once the contention window closes
- High consumed capacity numbers appear because the same key is retried by multiple clients
- Logs show overlapping TransactWriteItems or Put/Update/Delete operations targeting the same primary key
Common causes
- Two TransactWriteItems operations race to modify the same primary key simultaneously
- A non-transactional PutItem, UpdateItem, or DeleteItem runs while a concurrent transaction already touches the same record
- TransactGetItems reading the same item at the same time another transaction is writing it
- Hot partitions that serve a storm of concurrent writers for the same user ID or order ID
- Very large transactions that touch many items keep locks longer, increasing the chance of a later request starting before the first finishes
- Retry loops that immediately reissue the same transaction instead of backing off, amplifying the conflict storm
How to fix "TransactionConflictException: Operation failed due to a conflict with another request"
Start by looking at the TransactionConflict metric for the table and examine the CancellationReasons returned by the SDK so you understand which partition keys are involved.
\\\bash
aws cloudwatch get-metric-statistics \
--namespace "AWS/DynamoDB" \
--metric-name "TransactionConflict" \
--dimensions Name=TableName,Value=YourTableName \
--statistics Sum \
--start-time "$(date -u -d '10 minutes ago' +%Y-%m-%dT%H:%M:%SZ)" \
--end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--period 300 \
--region us-east-1
\\\
If you see CancellationReasons entries with Code=TransactionConflict (Java SDK gives a structured list, other languages include the same code in the error message), you know which item lost the race and can correlate it with the partition key in CloudWatch.
The conflict is retryable, but you must back off so all clients do not hammer the same key.
\\\`javascript
async function runTxn(params) {
for (let attempt = 0; attempt < 6; attempt++) {
try {
return await client.send(new TransactWriteCommand(params));
} catch (error) {
const isConflict =
error.name === 'TransactionConflictException' ||
(error.name === 'TransactionCanceledException' &&
error.CancellationReasons?.some(reason => reason.Code === 'TransactionConflict'));
if (!isConflict || attempt === 5) throw error;
const delay = Math.min(1000 * 2 ** attempt, 5000) + Math.random() * 100;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
\\\`
This spreads retries out and gives the transaction holding the partition time to finish before the next attempt runs.
Small, targeted transactions hold item locks for a shorter period. Split mega-transactions into separate operations when possible, and avoid batching unrelated partitions together. Also consider adding a lightweight lock record (with TTL) or staging queue so only one writer touches the hotspot at a time. When the conflict comes from non-transactional writes, move them into the same controlled transaction so DynamoDB can coordinate them atomically instead of letting each call grab the lock independently.
Use a condition expression to check a version counter or lock token before you commit, which lets you fail fast instead of enforcing the lock inside DynamoDB. For example:
\\\bash
aws dynamodb update-item \
--table-name YourTable \
--key '{ "pk": { "S": "user#123" } }' \
--update-expression "SET lockVersion = lockVersion + :one" \
--condition-expression "attribute_not_exists(lockVersion) OR lockVersion = :expected" \
--expression-attribute-values '{ ":one": { "N": "1" }, ":expected": { "N": "5" } }'
\\\
When the condition fails, you can hold off before trying again, which reduces the number of actions that ever make it far enough to trigger a TransactionConflictException.
Advanced notes
Each TransactionConflictException increments the TransactionConflict CloudWatch metric for the table, so spikes there are the quickest way to spot a hotspot. When TransactWriteItems is involved, the resulting TransactionCanceledException contains CancellationReasons entries with Code=TransactionConflict that map directly to the item that lost the race. The exception can hit both transactional and non-transactional writes because DynamoDB does not let two operations modify the same item at the same time—it always fails the newcomer to guarantee serializability.
Frequently asked questions
- What does "TransactionConflictException: Operation failed due to a conflict with" mean?
- The TransactionConflictException is DynamoDB telling you that it could not obtain a lock on your primary key because another request already held it. Serializable isolation around transactions means that once one operation begins mutating an item, other operations that reference that same item—whether they are TransactWriteItems / TransactGetItems or even non-transactional PutItem, UpdateItem, or DeleteItem calls—will be rejected with this message instead of allowing both to proceed. The "Operation failed due to a conflict with another request" text is the service tracing which request claimed the partition first and why the new call cannot commit.
- How do I fix "TransactionConflictException: Operation failed due to a conflict with"?
- DynamoDB raises this error when your transaction or item-level write collides with another request touching the same key, so it rejects the new operation to keep the data consistent.
- What causes "TransactionConflictException: Operation failed due to a conflict with"?
- Two TransactWriteItems operations race to modify the same primary key simultaneously A non-transactional PutItem, UpdateItem, or DeleteItem runs while a concurrent transaction already touches the same record TransactGetItems reading the same item at the same time another transaction is writing it
- Is the "TransactionConflictException: Operation failed due to a conflict with" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚DynamoDB Official Documentation
- 📖DynamoDB Developer Guide – Transaction conflict handling(Official Docs)
- 📖CloudWatch metric: TransactionConflict(Official Docs)