You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Error mapping: 422 / 409 / 408 / 410 fall through to bare KalshiError (+ tests for fallback) #201
_map_error only branches on 400 → KalshiValidationError, 401/403 → KalshiAuthError, 404 → KalshiNotFoundError, 429 → KalshiRateLimitError, and >=500 → KalshiServerError. Everything else falls through to bare KalshiError:
422 Unprocessable Entity — semantic validation (e.g. count > position_limit on order create). Kalshi uses 422 for the same recovery flow as 400 but callers except KalshiValidationError will miss it.
409 Conflict — duplicate client_order_id, double-cancel races. No way to retry the right way without parsing the message.
410 Gone — resource deleted permanently; same handling as 404 in many flows.
No test asserts the fallthrough (type(err) is KalshiError, not a subclass), so a future refactor that re-classifies (e.g. 422 → KalshiValidationError) breaks no test.
_map_error body fallback chain (body.get('message') → body.get('error') → response.text → f'HTTP {status}') also has no test for the terminal 'HTTP {status}' branch (empty body AND no JSON).
Location
kalshi/_base_client.py:36-74 — _map_error
tests/test_client.py:46-156 — TestErrorMapping
Recommended fix
Code
Route 422 to KalshiValidationError (same shape as 400).
Add KalshiConflictError(KalshiError) for 409.
Either route 408 to KalshiServerError with status_code=408 (so the retry policy can retry it under the separate "Cloudflare 5xx" change) or document the current pass-through behavior.
Document the full 1:1 status → exception table in docs/errors.md.
Tests
@pytest.mark.parametrize("status,exc_type", [ (400, KalshiValidationError), (422, KalshiValidationError), # new (409, KalshiConflictError), # new (401, KalshiAuthError), (403, KalshiAuthError), (404, KalshiNotFoundError), (429, KalshiRateLimitError), (408, KalshiError), # pin current behavior or assert new (410, KalshiError), (451, KalshiError), (500, KalshiServerError), (599, KalshiServerError),])deftest_status_maps_to_typed_exception(status, exc_type): ...
# Body fallback chaindeftest_empty_body_falls_back_to_http_status_message(): ...
deftest_html_body_propagates_as_message(): ...
deftest_body_error_secondary_key_used(): ...
Activity
feat(errors): add Conflict/Timeout/PoolExhausted; structure WS error …