x402 icon indicating copy to clipboard operation
x402 copied to clipboard

Fix concurrent payment request bug in Python HttpxHooks

Open madisoncarter1234 opened this issue 2 months ago • 2 comments

Summary

Fixes a critical bug where the Python HttpxHooks class prevented concurrent payment requests from succeeding. Only the first request would succeed while all others would fail with 402 errors without attempting payment.

Resolves #398

Problem

The HttpxHooks class used a single shared _is_retry boolean flag across all concurrent requests:

class HttpxHooks:
    def __init__(self, client: x402Client):
        self.client = client
        self._is_retry = False  # ❌ Shared across ALL requests

Race condition:

  1. Request A hits 402 → _is_retry = False → sets _is_retry = True → starts payment
  2. Request B hits 402 → _is_retry = Trueshort-circuits, returns 402 immediately
  3. Requests C, D, E → same as B, all fail with 402

Additional issues:

  • Flag was never reset after successful payment (only in exception handlers)
  • No per-request isolation

Solution

Replace the single boolean flag with a set that tracks each request individually:

class HttpxHooks:
    def __init__(self, client: x402Client):
        self.client = client
        self._retrying_requests = set()  # ✅ Track each request individually

How it works:

  • Use id(request) as a unique identifier for each request
  • Add request ID to set when starting retry
  • Remove request ID from set after completion (success or error)
  • Each concurrent request processes payment independently

Changes

  • python/x402/src/x402/clients/httpx.py:

    • Replaced _is_retry boolean with _retrying_requests set
    • Track requests using id(response.request)
    • Clean up tracking in all code paths (success + error handlers)
  • python/x402/tests/clients/test_httpx.py:

    • Updated tests to use _retrying_requests set instead of _is_retry flag
    • Tests now verify requests are removed from set after completion

Impact

This fix enables:

  • ✅ AI agents making concurrent batch requests to paid endpoints
  • ✅ Multiple simultaneous API calls from the same client
  • ✅ High-throughput applications with parallel paid endpoint access
  • ✅ Load testing of paid endpoints

Testing

All existing tests updated and passing. The fix maintains the same behavior for single requests while enabling proper concurrent request handling.

madisoncarter1234 avatar Oct 27 '25 19:10 madisoncarter1234

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

cb-heimdall avatar Oct 27 '25 19:10 cb-heimdall

@madisoncarter1234 is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Oct 27 '25 19:10 vercel[bot]