You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug: Redis layer fails the invocation instead of retrying when a record expires between SET NX and GET #8727
For contributors, human or agent. Comment here to claim this issue and wait for the assignment before opening a PR; if two PRs show up, the assignee's stays. AI-assisted work is welcome, say so in the PR and tell us how you verified it: run the tests yourself and paste what you saw, do not describe runs you did not do. Read AGENTS.md first, it has the commands and the rules the CI enforces. This goes into 3.41.0.
Expected Behaviour
When a Redis record expires between the SET NX that fails and the GET that follows, the Redis layer behaves like the DynamoDB layer: it raises IdempotencyInconsistentStateError, which the handler's retry loop turns into a retry, and the invocation succeeds.
Current Behaviour
In CachePersistenceLayer._put_record, the GET after a failed SET NX goes through _get_record, which raises IdempotencyItemNotFoundError. That exception is not handled there, escapes _put_record and is wrapped as IdempotencyPersistenceLayerError, so the invocation fails for a race that is expected and recoverable.
Code snippet
# fake client: SET NX returns None (key existed), the following GET returns None (key expired in between)layer=CachePersistenceLayer(client=racy_client)
@idempotent_function(data_keyword_argument="order", persistence_store=layer)defprocess(order):
return"ok"process(order={"id": 1}) # IdempotencyPersistenceLayerError, expected: retried and "ok"
Compare with DynamoDBPersistenceLayer._put_record, where the equivalent race raises IdempotencyInconsistentStateError.
Possible Solution
In aws_lambda_powertools/utilities/idempotency/persistence/redis.py, _put_record: catch IdempotencyItemNotFoundError around the read that follows the failed SET NX and raise IdempotencyInconsistentStateError. Add a test with a fake client that returns None on that GET and assert the decorated function runs.
Item 10 of the Idempotency audit in #8603. No AWS resources needed.
I've reviewed the Redis persistence implementation and the idempotency retry handling.
My understanding is that when Redis returns None for SET NX, the subsequent GET can also return None if the existing record expires between those operations. This currently results in an unrecoverable persistence-layer error instead of a retry.
My proposed approach is to:
Catch IdempotencyItemNotFoundError around the subsequent _get_record() call in _put_in_progress_record() and raise IdempotencyInconsistentStateError.
Verify that this exception propagates through _process_idempotency() to the existing retry loop without being wrapped as IdempotencyPersistenceLayerError.
Add a regression test using a fake Redis client to reproduce the race and verify successful recovery through the public idempotency API.
I'd like to work on this issue and would appreciate being assigned.
I've implemented the fix for the Redis idempotency race condition and added regression tests covering the inconsistent state and successful retry behavior.
I've also run the Redis and broader idempotency functional tests, Ruff, Mypy, and the pre-commit hooks. All passed.
I've prepared the PR with the test results and verification details included.
This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.
Activity
coughlmao commentedon Oct 31, 2026
Hi @leandrodamascena! I'd like to contribute to this issue.
I've reviewed the Redis persistence implementation and the idempotency retry handling.
My understanding is that when Redis returns None for
SET NX, the subsequentGETcan also return None if the existing record expires between those operations. This currently results in an unrecoverable persistence-layer error instead of a retry.My proposed approach is to:
IdempotencyItemNotFoundErroraround the subsequent_get_record()call in_put_in_progress_record()and raiseIdempotencyInconsistentStateError._process_idempotency()to the existing retry loop without being wrapped asIdempotencyPersistenceLayerError.I'd like to work on this issue and would appreciate being assigned.
Thank you!
leandrodamascena commentedon Nov 1, 2026
@coughlmao it's yours, assigning you now. Go ahead with the PR, and say in the description how you ran the tests.
coughlmao commentedon Nov 1, 2026
Hi @leandrodamascena.
Thank you for assigning me issue #8727.
I've implemented the fix for the Redis idempotency race condition and added regression tests covering the inconsistent state and successful retry behavior.
I've also run the Redis and broader idempotency functional tests, Ruff, Mypy, and the pre-commit hooks. All passed.
I've prepared the PR with the test results and verification details included.
powertools-for-aws-oss-automation commentedon Nov 14, 2026
Warning
This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.