-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
When calling get_x402_access_token() in the Python SDK, passing plan_id as an int instead of a str causes the backend to return a generic HTTP 500 with no indication of the type issue. Users spend significant time debugging.
How it happens
# This fails with generic 500
token = payments.x402.get_x402_access_token(plan_id=12345)
# => PaymentsError: Failed to create X402 permission (HTTP 500)
# This works
token = payments.x402.get_x402_access_token(plan_id="12345")The function signature declares plan_id: str but Python doesn't enforce type hints at runtime. The int gets serialized as JSON number {"planId": 12345} instead of string {"planId": "12345"}.
Root cause in SDK
In payments_py/x402/token.py:131-136, plan_id is placed directly into the request body without type validation. The error handling at lines 168-177 wraps the HTTPError as PaymentsError.internal(), discarding type-specific context.
Scope
Not limited to plan_id — any string field receiving a non-string type (agent_id as int, max_amount as int) could trigger the same backend 500. Unclear if TypeScript SDK has the same issue with BigInt/number.
Proposed Solutions
- SDK-side type coercion —
plan_id = str(plan_id)before building the request. Silently fixes the issue. (Very low effort) - SDK-side type validation — Raise
TypeErrorwith"plan_id must be a string, got int"before the API call. (Very low effort) - Backend input validation — Return
400 Bad Requestwith{"error": "INVALID_TYPE", "field": "planId", "expected": "string"}. (Fixes for all SDKs) - Pydantic model for request body — Catch type mismatches with clear messages before HTTP call.
- Verify TypeScript behavior — Test if TS SDK has same issue with
number/BigInt.
Additional Context
- Reported at the March 2026 hackathon event
- Specific instance of the broader "unhelpful error messages" problem
- Proposals build(deps): bump idna from 3.6 to 3.7 #1 or build(deps): bump jinja2 from 3.1.3 to 3.1.4 #2 can ship immediately as a SDK-side fix