Skip to content

fix(idempotency): return stored falsy responses on replay - #8701

Merged
leandrodamascena merged 2 commits into
aws-powertools:developfrom
thebadalov:fix/idempotency-falsy-response-replay
Nov 4, 2026
Merged

leandrodamascena merged 2 commits into
aws-powertools:developfrom
thebadalov:fix/idempotency-falsy-response-replay

Conversation

@thebadalov

Copy link
Copy Markdown
Contributor

Issue number: closes #8700

Summary

Changes

IdempotencyHandler._handle_for_status now checks response_dict is not None before deserializing the stored response, the same check _get_function_response already uses when saving it.

Added test_idempotent_function_falsy_response_replay, parametrized over 0, False, "", [] and {}. Each case calls the function twice with the same payload and checks that the second call returns the same value and type without running the function again. All five cases fail on the current develop and pass with the fix.

User experience

  • Before: a function returning 0, False, "", [] or {} got None back on every replay.
  • After: the replay returns the stored value. Functions that return None and truthy values behave the same as before.

Testing

  • tests/functional/idempotency and tests/unit/idempotency: 207 passed
  • ruff format, ruff lint, mypy and ty: clean
  • Checked against a local Redis server with CachePersistenceLayer for 0, False, "", [], {}, None and a truthy value

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

_handle_for_status only deserialized the stored response when it was
truthy, so a function returning 0, False, "", [] or {} got None back on
every replay, even though the value was saved correctly.

Check for None instead, matching the write path in
_get_function_response.

@leandrodamascena leandrodamascena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @thebadalov, confirmed against real DynamoDB and Valkey: on develop every falsy return (0, False, "", [], {}) comes back as None on replay, with your change each one comes back as the stored value with the right type, and None and truthy values are unchanged. The dataclass serializer path is fine too.

I'm approving now. This goes out in 3.40.0, so it will sit here for a while before I merge it. No rebase needed in the meantime, and you'll be credited in the release notes.

@sonarqubecloud

sonarqubecloud Bot commented Nov 4, 2026

Copy link
Copy Markdown

@codecov

codecov Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.01%. Comparing base (083460d) to head (4eef493).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #8701   +/-   ##
========================================
  Coverage    97.01%   97.01%           
========================================
  Files          321      321           
  Lines        16431    16431           
  Branches      1484     1484           
========================================
  Hits         15940    15940           
  Misses         350      350           
  Partials       141      141           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@leandrodamascena
leandrodamascena merged commit d7b3024 into aws-powertools:develop Nov 4, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Denotes a PR that changes 30-99 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: idempotent functions return None on replay when the stored response is falsy (0, False, "", [], {})

2 participants