Skip to main content

idemcheck

Find the HTTP handlers that will double-charge when a client retries.

A client retries because the network lied. If your handler writes before it can answer, the retry writes again. Idempotency libraries exist for every framework, and nothing tells you which of your routes is missing the guard.

$ idemcheck examples/
idemcheck: 1 finding(s) across 2 mutating route(s) in 1 file(s), worst high

[HIGH] examples/app.py:12 (missing-idempotency)
  route: POST /charge
  why:   charge with no idempotency key, dedupe store or unique constraint
  calls: db.orders.insert_one, db.session.commit
  fix:   read an Idempotency-Key and store it before the first write, or make the write
         itself unique so a second delivery cannot land twice

The example file contains two POST handlers: /charge writes and is flagged, /charge-safe reads an Idempotency-Key first and is not.

Install

pipx install idemcheck     # once it is on PyPI
# or straight from the repo:
pipx install git+https://github.com/mgkvibez/idemcheck

Python 3.9 or newer. No runtime dependencies.

Usage

idemcheck                      # scan the current directory
idemcheck src/ app.py          # scan specific paths
idemcheck --json | jq .        # machine-readable
idemcheck --fail-on medium     # stricter gate, for a payments service
idemcheck --include-tests      # include tests/ (skipped by default)

Exit codes: 0 nothing at or above the threshold, 1 findings, 2 usage error.

--fail-on defaults to high, so a PUT that writes without a guard reports and exits 0 until you ask otherwise.

What it looks for

A handler is a finding when it answers a mutating method and calls something that writes and nothing in it mentions a guard.

Severity When
high POST, or any outbound money/HTTP send, with unguarded writes
medium PUT/PATCH/DELETE with unguarded writes (they should already be idempotent)

Writes are recognised by method name: commit, flush, insert*, update*, delete*, save, upsert, execute, add, plus money movement like charge, capture, transfer, refund, and queue sends like delay and enqueue.

A guard is recognised by any of: idempotency, idempotent, idem_key, request_id, dedupe, dedup_key, nonce, client_reference, get_or_create, update_or_create, on_conflict, unique_together.

Routes are read from the decorator: @app.post, @router.put, and the methods=[...] keyword on @app.route and @app.api_route (Flask and FastAPI).

What this deliberately does not do

Static analysis cannot prove a handler is safe, and this tool does not claim to.

  • A guard installed by a decorator defined in another module is invisible here.
  • An ORM that commits on your behalf, or a write hidden inside a helper function, is invisible here.
  • Django class-based views, generic routers and dynamically constructed handlers are not detected at all.
  • A handler that mentions request_id incidentally is treated as guarded, even when it is not. That is a false negative, and it is the direction this tool errs on purpose: a checker that cries wolf gets uninstalled after one afternoon.

The clean line is exactly what it says: no unguarded write was recognised.

Tests

python -m pytest -q      # 19 tests
bash scripts/verify.sh   # the release gate

Contributing

Adding a framework means teaching the decorator reader one more name in analyze.py, and adding a fixture that proves both the flagged and the guarded case. A rule that cannot show both is not ready.

License

MIT.

Metadata

Release files for idemcheck 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for idemcheck 0.1.0
File Size Uploaded Provenance Actions
idemcheck-0.1.0.tar.gz 10.0 kB With provenance Details for idemcheck-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for idemcheck 0.1.0
File Interpreter ABI Platform Actions
idemcheck-0.1.0-py3-none-any.whl Python 3 none any Details for idemcheck-0.1.0-py3-none-any.whl

Total release size: 19.3 kB

Release files / idemcheck-0.1.0.tar.gz

Download URL idemcheck-0.1.0.tar.gz
Size 10.0 kB
Tags Source
SHA-256 checksum
How to use checksums
fc1c4b4dfc31201e77ae69e2050d9b873ff17da9c14312fd0928606e2f8f572a
BLAKE2b-256 checksum
How to use checksums
e1f80303e4c20c870047b453c3302a0eaefc4b8a56418706e96d64915d19f7c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / idemcheck-0.1.0-py3-none-any.whl

Download URL idemcheck-0.1.0-py3-none-any.whl
Size 9.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
33ccc78efbe8f32900d6a926310933fbe67553dfcebe63df97d358633768246b
BLAKE2b-256 checksum
How to use checksums
0bfec5696e8be24e2803dc567018f4f141811ff54bd43d01feef398b4f2747a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for idemcheck 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for idemcheck-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page