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.

  5. Log token and elapsed time on each retry. The 5-second guidance is documented — your logs should show whether retries arrive too early.

Path in DynoTable

Inspect the items a long transaction touches before you tune timeouts — open them with ⌘K and confirm no hot-key contention from parallel writers. Staging (⌘S) lets you replay a smaller transaction against dev data first.

Estimate transactional write cost with the pricing calculator. Switch profiles with ⌘P; Test Connection on Settings → Profiles. See Connect to AWS and Install.

Sources

References

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

Work with DynamoDB without the Console

A fast DynamoDB desktop client that runs the real SQL DynamoDB can’t — JOINs, GROUP BY, aggregates — with visual editing and an AI agent on your own Bedrock keys.

Free 30-day trial, no credit card — then the Free plan with no time limit.