Skip to content

fix: Raise a Seam error for a success response that is malformed - #638

Open
razor-x wants to merge 1 commit into
claude/python-sdk-audit-o2iid9-04-wait-optionfrom
claude/python-sdk-audit-o2iid9-05-invalid-response
Open

fix: Raise a Seam error for a success response that is malformed#638
razor-x wants to merge 1 commit into
claude/python-sdk-audit-o2iid9-04-wait-optionfrom
claude/python-sdk-audit-o2iid9-05-invalid-response

Conversation

@razor-x

@razor-x razor-x commented Aug 27, 2026

Copy link
Copy Markdown
Member

What

A 2xx response with an unexpected envelope — a proxy rewrite, a maintenance page served with a JSON content type, a renamed response key — escaped the SDK's error hierarchy entirely: generated routes unwrapped res["device"] inline at ~240 sites, so callers got a bare KeyError, TypeError: string indices must be integers, or a raw json.decoder.JSONDecodeError (SDK audit finding M3; same fix as JS #1005 and PHP #475).

  • New SeamHttpInvalidResponseError(SeamError) with path and response_key attributes and the same message shape as the JS/PHP SDKs: Seam returned an invalid response for {path}: expected "{key}", {reason}.
  • New hand-written seam/response.py with unwrap / unwrap_list helpers that verify the body is an object, the key is present, and the value has the right shape.
  • The route codegen template routes all three return forms (object, list, action-attempt) through the helpers — a template change, so it lands at every generated site at once. The two hand-written poll sites in seam/modules/action_attempts.py use the same helper.
  • _handle_response now hands an unparseable JSON body on as text instead of leaking JSONDecodeError, so it surfaces as the same invalid-response error (this matches the JS SDK, where axios keeps the string).

Depends on #634 (SeamError base) and is stacked on #637; the diff shrinks as those merge.

Testing

New test/invalid_response_test.py (sync + async, recording server, pinned messages): missing key, JSON null/string body, HTML page with a JSON content type, plain-text response, non-object value under the key, non-list value under a list key, and a malformed poll response mid-wait.

Revert check: with seam/routes/devices.py and seam/client.py reverted, the tests fail with the audit's exact symptoms (KeyError: 'device', TypeError: string indices must be integers, raw JSONDecodeError).

Regeneration is drift-free at this head; the generated diff touches exactly the unwrap sites. Full suite: 216 passed; mypy, pylint (10.00), black clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y1RzepycXEYA3LStfjt8cY


Generated by Claude Code

@razor-x
razor-x requested a review from a team as a code owner August 27, 2026 21:22
@razor-x
razor-x changed the base branch from main to claude/python-sdk-audit-o2iid9-04-wait-option August 28, 2026 00:15
@razor-x
razor-x force-pushed the claude/python-sdk-audit-o2iid9-05-invalid-response branch from 87cab53 to 38dc6ab Compare August 28, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants