TransactionInProgressException

TL;DR — A TransactWriteItems retry carried the same ClientRequestToken as an attempt that is still executing. This is usually your client timing out faster than the transaction completes, so the SDK's retry collides with the in-flight original. Keep retrying with backoff — a later retry after the original finishes returns the idempotent success — and tune timeouts so at least one retry lands after ~5 seconds.

What it means

TransactionInProgressException: The transaction with the given request token
is already in progress.

ClientRequestToken makes TransactWriteItems idempotent: identical calls within a 10-minute window count as one transaction. While the first attempt is still being processed, a second call with the same token can't be answered yet — it's neither a duplicate of a completed transaction nor a new one — so DynamoDB rejects it with this exception. It's a timing signal, not a data error.

Why it happens

  • Client timeout shorter than transaction latency — the request timeout fires, the SDK retries, and the retry arrives while the original transaction is still committing.
  • Aggressive retry policy — very short backoff means several retries can pile onto a transaction that needs a few seconds.
  • Two callers sharing one token — separate processes deliberately (or accidentally) issuing the same ClientRequestToken concurrently.

How to fix it

  1. Let the retries continue with exponential backoff — once the in-flight transaction completes, a retry with the same token returns success without applying the writes twice. Treat this exception as retryable.

  2. Tune timeouts per the documented guidance so a retry can land after the transaction settles:

    • allow at least one retry to be processed after 5 seconds have elapsed since the first attempt;
    • set the per-request timeout to about 1 second or higher;
    • keep the socket timeout slightly below the request timeout;
    • use exponential backoff between attempts.
  3. Don't rotate the token on retry — generating a fresh ClientRequestToken per attempt silently converts retries into new transactions (double-applying the writes). Same intent, same token, for up to 10 minutes:

    const token = randomUUID(); // one token per logical transaction
    await client.send(new TransactWriteItemsCommand({TransactItems, ClientRequestToken: token}));
  4. Serialize deliberate concurrent callers — if two workers can submit the same logical transaction, make one the owner or route both through a queue.

If transactions run long enough to trip timeouts, check what they're contending on — the DynoTable desktop app lets you inspect the items involved, and the DynamoDB pricing calculator shows what the doubled write capacity of transactional writes costs.

References

Last verified 2026-07-13 against the official AWS documentation linked above.

Work with DynamoDB without the Console

DynoTable is a fast desktop client for DynamoDB — browse tables, run SQL-style queries, and edit items locally.