payinOPERATIONS MANUAL

Latest articles

Stripe 429 diagnosis: rate limits, concurrency and object locks need different queues

Use Stripe limiter reasons and lock_timeout to choose rate pacing, in-flight caps or object-scoped serialization.

Published; sources checked:

Stripe API admission scheduling and 429 classification; excludes idempotency retention, search freshness, export completeness and general retry-budget tutorials. Documentation research only.

Classify the 429 before changing the queue

A public issue titled “Handle Stripe RateLimitError” contains a 429 response whose actual error code is lock_timeout. The report concerns repeated payment-page access, not a measured account-wide throughput ceiling. It demonstrates why an exception name is insufficient for diagnosis; it does not establish incident frequency.[2]

Stripe distinguishes requests per second, simultaneously active requests, and contention for an object lock. These require different scheduling controls.[1] This guide addresses admission to the API, not idempotency-key retention, search freshness, or export completeness.

Rate and concurrency are independent budgets

The documented global rate is 100 requests per second in live mode and 25 in a sandbox; individual endpoints default to 25 unless otherwise noted. These are ceilings, not promised usable throughput. Different object IDs still share the same named endpoint limit.[1]

Concurrency counts requests still in progress. Long-running list requests and expansions can consume capacity even when request starts remain modest.[1] As illustrative arithmetic, ten starts per second with a steady two-second duration means roughly twenty requests overlap. This is not a Stripe benchmark or a concurrency allowance.

Recommended design: use a token bucket to pace starts and a separate semaphore to bound in-flight work. Apply shared account and endpoint controls across workers; a per-process limiter multiplies its allowance when replicas increase. Treat the token bucket as pacing, not permission to burst to the documented maximum.

Route each reason to its matching control

  1. Capture the original response status, Stripe-Rate-Limited-Reason, error code, account and mode, named endpoint, object references, duration, and request ID when available. Preserve headers through proxies before diagnosing a missing header.
  2. For global-rate, reduce starts across the account. For endpoint-rate, slow that endpoint while retaining the account-wide budget. These are distinct documented limit scopes.[1]
  3. For global-concurrency or endpoint-concurrency, reduce the corresponding simultaneous work. Inspect slow calls rather than merely increasing the gap between retries.[1]
  4. For resource-specific, check that resource’s documented operation and window. For example, PaymentIntent updates have a per-object hourly limit; a general per-second bucket cannot represent every resource constraint.[1]
  5. Without a limiter header, do not automatically label the response account throttling. Stripe says such a 429 is not a rate-limit response and might be a lock timeout. Confirm lock_timeout in the error body; unexplained responses remain unclassified.[1]

Serialize conflicting objects, not the entire account

Stripe recommends queueing mutations on the same object sequentially; related-object access can also contend. An internal Stripe background process can hold a lock, so local serialization cannot eliminate all lock timeouts.[1]

Consider a hypothetical migration running alongside customer updates. If long list calls trigger endpoint-concurrency, reduce the migration’s in-flight slots and examine expensive expansions. If two jobs modifying the same object return lock_timeout, route them through one object-scoped queue instead. Keep independent objects eligible for bounded parallelism. Neither response justifies adding more workers as the first action.

Make the queue key include account context and the shared business object. Where operations on different child IDs touch a common parent, investigate a parent-level serialization key. This is an application design recommendation, not a complete map of Stripe’s internal locks.

Recovery checklist

  • Use bounded retries with exponential backoff and randomness, as Stripe recommends. Inspect SDK retry configuration: its documented automatic behavior distinguishes lock-timeout 429s from rate-limit 429s.[1]
  • Keep retries inside the same admission controls; do not let a retry queue bypass account or endpoint limits. Record initial calls separately from extra attempts.
  • Track reason counts, in-flight requests, latency, queue age and object contention. Preserve existing mutation identity and reconciliation rules rather than changing keys to escape congestion.
  • Propose tests for every reason branch, stripped headers, slow requests and repeated object mutations. Stripe discourages using sandbox load tests as production-capacity evidence because limits and latency differ.[1] No such tests were executed here.

Sources and boundaries

Checked September 23, 2026. Documentation research only; no live-account test or throughput guarantee. General scheduling guidance assumes an eligible Stripe account and available endpoints. The cited guide does not specify a country restriction for these general mechanisms; product-specific eligibility still requires checking.

  • [1] Rate limits — Stripe. Publication and update dates not stated; retrieved September 23, 2026. Official behavior and current documented ceilings, not an account-specific capacity commitment.
  • [2] Handle Stripe RateLimitError. Published and updated March 5, 2022; retrieved September 23, 2026. Historical third-party report, used only as qualitative demand evidence, not current SDK verification.

More guides