can1357/oh-my-pi · error · GitHubError

proxy returned malformed pr payload

Error message

proxy returned malformed pr payload

What it means

GitHubError(500) raised by _pr_from when the proxy's pull-request payload is not a JSON object. get_pull_request and open_pull_request both require a dict with repo/number/html_url; any scalar or null body means the proxy broke its PR contract.

Source

Thrown at python/robomp/src/proxy_client.py:722

        submitted_at=str(data.get("submitted_at") or ""),
    )


def _pr_file_from(data: Any) -> PullRequestFileInfo:
    if not isinstance(data, dict):
        raise GitHubError(500, "proxy returned malformed pr_file payload")
    return PullRequestFileInfo(
        path=str(data.get("path") or ""),
        status=str(data.get("status") or ""),
        additions=int(data.get("additions") or 0),
        deletions=int(data.get("deletions") or 0),
        patch=str(data.get("patch") or ""),
    )


def _pr_from(data: Any) -> PullRequestInfo:
    if not isinstance(data, dict):
        raise GitHubError(500, "proxy returned malformed pr payload")
    return PullRequestInfo(
        repo=str(data["repo"]),
        number=int(data["number"]),
        html_url=str(data["html_url"]),
        head_ref=str(data.get("head_ref") or ""),
        base_ref=str(data.get("base_ref") or ""),
        state=str(data.get("state") or "open"),
        author=str(data.get("author") or ""),
        head_repo=str(data.get("head_repo") or ""),
        title=str(data.get("title") or ""),
        body=str(data.get("body") or ""),
        head_sha=str(data.get("head_sha") or ""),
    )


__all__ = ["GitHubProxyClient", "ProxyGitTransport"]

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the raw proxy response for the PR endpoint to see the actual non-dict body.
  2. For open_pull_request: check whether the PR was actually created (list PRs / get by number) before retrying, to avoid duplicates.
  3. Align the proxy version with the client schema; redeploy or upgrade the proxy.
  4. Retry get_pull_request with backoff if the failure is transient.
  5. Report the malformed response to the proxy maintainers with the exact body.

Example fix

# before
pr = client.open_pull_request("org/repo", head, base, title)  # GitHubError 500

# after
try:
    pr = client.open_pull_request("org/repo", head, base, title)
except GitHubError as e:
    if e.status == 500:
        # PR may exist; look it up instead of re-opening
        pr = next((p for p in client.list_issues("org/repo") if p.is_pull_request and p.title == title), None)
    else:
        raise
Defensive patterns

Strategy: try-catch

Validate before calling

body = resp.json()
if not isinstance(body, dict) or "html_url" not in body:
    raise RuntimeError(f"proxy pr payload not an object: {body!r}")

Type guard

def is_pr_payload(data: object) -> bool:
    return isinstance(data, dict) and "repo" in data and "number" in data and "html_url" in data

Try / catch

try:
    pr = client.open_pull_request("org/repo", head, base, title)
except GitHubError as e:
    if e.status == 500 and "malformed pr payload" in str(e):
        pr = lookup_pr_by_head("org/repo", head)  # may exist; avoid duplicate PRs
    else:
        raise

Prevention

When it happens

Trigger: Calling get_pull_request() for an existing PR when the proxy returns a non-object body, or open_pull_request() when creation succeeds at GitHub but the proxy acknowledges with null/a string instead of the PR object.

Common situations: Proxy ACK-only create returning "created" instead of the object; proxy error page (HTML/plain text) parsed as a scalar; stale proxy with a different PR envelope; middleware rewriting response bodies.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/b2b6fb84cf699227. Report an issue: GitHub.