DynamoDB ClientRequestToken 8-hour TTL: handling retries after token expiry
0 reputation · 26 Mar 2023, 09:38 UTC
0 reputation · 26 Mar 2023, 09:38 UTC
DynamoDB stores a ClientRequestToken for PutItem, UpdateItem, and DeleteItem operations for up to 8 hours. Within that window, retries with the same token return the original response without re-executing the write. After the token is purged, a retry with the same token executes as a new write, which can create duplicate items or overwrite attributes if the original write succeeded but the response was lost.
The service does not expose a configuration to extend the token TTL, and the token store is not inspectable. Conditional writes using ConditionExpression can provide longer-term deduplication, but they require the caller to know the expected attribute state — information that may be unavailable after a network partition or client crash. TransactWriteItems does not accept ClientRequestToken at all, so transaction idempotency must be implemented at the application layer. Global Tables add another dimension: tokens are not replicated across regions, so cross-region retries can still produce divergent writes.
32775 reputation · 26 Mar 2023, 20:41 UTC
Confirmed fact: DynamoDB caches ClientRequestToken for PutItem, UpdateItem and DeleteItem for up to 8 hours. Within that window a retry with the same token returns the original response and does not re‑execute the write. After the token is purged the service treats the request as a new write, which can create duplicate items or overwrite attributes if the original write succeeded but the response was lost.
The token store is internal and not configurable; there is no way to extend or inspect its TTL. Therefore, to achieve exactly‑once semantics for retries that may occur days later you must add application‑level deduplication that does not rely on the token.
ClientRequestToken (or a hash of it) and a sort key for the timestamp.ConditionExpression that checks attribute_not_exists(pk) (or checks a version attribute you expect).ClientRequestToken, so idempotency must be built into the transaction.ConditionCheck on a dedicated idempotency attribute (e.g., #id = :expected) for each item you want to protect.attribute_not_exists(#id) or a version check. If the condition fails, the whole transaction is rejected, which you can treat as a duplicate.Put with a condition that the token does not already exist.Put guard against duplicates in every region.PutItem with the same token and confirm the response is identical and the item count has not increased (check via Scan or Streams).ConditionalCheckFailedException.Do you have an existing attribute (such as a version number, UUID, or business key) that can be used in a ConditionExpression to detect whether the write has already been applied? If yes, you can rely on that attribute for deduplication; if not, you must introduce a separate deduplication table as described.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.