Measured on 0.2.0 with the Redis repository. After a charge of 1999 was recorded under key order-42, the same key came back with a different amount:
--- the same key again, with a different amount ---
requested amount 5, got back: charge_id='ch_1' amount=1999
Rule 1 on the agents page says the arguments are not part of the identity, so this is documented, and for a well-behaved client it never happens. It happens with a client that reuses keys by mistake (a key derived from the order id, then a second, different operation on the same order), and today the library answers such a request with a result for a different request and no signal that anything is off. Stripe rejects this with a 422 ("keys are for identical requests"), and I think that is the right shape.
Proposal: an optional fingerprint on the record. coordinate() takes fingerprint: str | None = None; the decorator takes a way to derive one from the call (a callable over the bound arguments, or a tuple of parameter names whose values are hashed after model_dump(mode="json") for Pydantic models). The fingerprint is stored on IdempotencyRecord (fingerprint: str | None, so existing records stay readable) and compared on a hit; a hit with a different fingerprint raises a new IdempotencyKeyReuseError carrying both fingerprints. That one must propagate through the coordinator rather than be swallowed: it is a caller error, not storage trouble, and rule 6 is about storage. No fingerprint supplied means today's behaviour, key only.
Script: measure.py in https://github.com/bedrock-python/bedrock-python.github.io/tree/docs/production-python-series/docs/blog/lab/2026-09-07-idempotency-keys. Related: the in-flight reservation issue filed alongside this one.
Measured on 0.2.0 with the Redis repository. After a charge of 1999 was recorded under key
order-42, the same key came back with a different amount:Rule 1 on the agents page says the arguments are not part of the identity, so this is documented, and for a well-behaved client it never happens. It happens with a client that reuses keys by mistake (a key derived from the order id, then a second, different operation on the same order), and today the library answers such a request with a result for a different request and no signal that anything is off. Stripe rejects this with a 422 ("keys are for identical requests"), and I think that is the right shape.
Proposal: an optional fingerprint on the record.
coordinate()takesfingerprint: str | None = None; the decorator takes a way to derive one from the call (a callable over the bound arguments, or a tuple of parameter names whose values are hashed aftermodel_dump(mode="json")for Pydantic models). The fingerprint is stored onIdempotencyRecord(fingerprint: str | None, so existing records stay readable) and compared on a hit; a hit with a different fingerprint raises a newIdempotencyKeyReuseErrorcarrying both fingerprints. That one must propagate through the coordinator rather than be swallowed: it is a caller error, not storage trouble, and rule 6 is about storage. No fingerprint supplied means today's behaviour, key only.Script:
measure.pyin https://github.com/bedrock-python/bedrock-python.github.io/tree/docs/production-python-series/docs/blog/lab/2026-09-07-idempotency-keys. Related: the in-flight reservation issue filed alongside this one.