{"record":{"id":"8d7c3bb7f356e941","repo":"can1357/oh-my-pi","slug":"proxy-returned-malformed-issue-payload","errorCode":null,"errorMessage":"proxy returned malformed issue payload","messagePattern":"proxy returned malformed issue payload","errorType":"exception","errorClass":"GitHubError","httpStatus":500,"severity":"error","filePath":"python/robomp/src/proxy_client.py","lineNumber":607,"sourceCode":"        html_url=str(data.get(\"html_url\") or \"\"),\n        asset_names=tuple(str(asset) for asset in data.get(\"asset_names\") or []),\n    )\n\n\ndef _repo_from(data: Any) -> RepoInfo:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed repo payload\")\n    return RepoInfo(\n        full_name=str(data[\"full_name\"]),\n        default_branch=str(data[\"default_branch\"]),\n        clone_url=str(data[\"clone_url\"]),\n        private=bool(data.get(\"private\", False)),\n    )\n\n\ndef _issue_from(data: Any) -> IssueInfo:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed issue payload\")\n    labels = data.get(\"labels\") or []\n    return IssueInfo(\n        repo=str(data[\"repo\"]),\n        number=int(data[\"number\"]),\n        title=str(data.get(\"title\") or \"\"),\n        body=str(data.get(\"body\") or \"\"),\n        state=str(data.get(\"state\") or \"open\"),\n        author=str(data.get(\"author\") or \"\"),\n        labels=tuple(str(x) for x in labels),\n        is_pull_request=bool(data.get(\"is_pull_request\", False)),\n    )\n\n\ndef _issue_summary_from(data: Any) -> IssueSummary:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed issue summary payload\")\n    return IssueSummary(\n        repo=str(data[\"repo\"]),","sourceCodeStart":589,"sourceCodeEnd":625,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy_client.py#L589-L625","documentation":"GitHubError(500) raised by _issue_from when the proxy response for a single issue is not a JSON object (dict). The library expects every issue payload from the GitHub proxy to be a mapping with required keys (repo, number); any non-dict (string, list, null) means the proxy protocol was violated. This is a server-side contract failure surfaced defensively to the client.","triggerScenarios":"Calling get_issue() when the proxy returns a non-object JSON body for the issue endpoint — e.g. a JSON array, a bare string, null, or an HTML/error page that was misparsed as JSON.","commonSituations":"Proxy deployed at a mismatched version returning an older/newer envelope; proxy error handler returning a JSON string or null instead of an object; misrouted endpoint returning a list; intermediary (gateway/LB) replacing the body with a plain-text or HTML error that got parsed as a scalar.","solutions":["Inspect the raw proxy response for the issue endpoint (curl the proxy URL) to see what non-dict body is actually returned.","Verify the proxy service version matches what this client expects and redeploy/restart it if it is stale or crashed.","Check proxy logs for the failing request — an upstream GitHub error is probably being passed through in the wrong shape.","Retry the request; if transient, add retry with backoff around get_issue().","If the proxy is third-party, report the malformed-payload contract violation with the response body."],"exampleFix":"# before\nissue = client.get_issue(\"org/repo\", 42)  # crashes with GitHubError 500\n\n# after\ntry:\n    issue = client.get_issue(\"org/repo\", 42)\nexcept GitHubError as e:\n    if e.status == 500:\n        raw = fetch_raw_issue(\"org/repo\", 42)  # inspect/log actual proxy body\n        raise RuntimeError(f\"proxy payload malformed: {raw!r}\") from e\n    raise","handlingStrategy":"try-catch","validationCode":"import json, requests\nresp = requests.get(f\"{PROXY_URL}/repos/org/repo/issues/42\")\nbody = resp.json()\nif not isinstance(body, dict):\n    raise RuntimeError(f\"proxy issue payload not an object: {body!r}\")","typeGuard":"def is_issue_payload(data: object) -> bool:\n    return isinstance(data, dict) and \"repo\" in data and \"number\" in data","tryCatchPattern":"from robomp.proxy_client import GitHubError\ntry:\n    issue = client.get_issue(\"org/repo\", 42)\nexcept GitHubError as e:\n    if e.status == 500 and \"malformed issue payload\" in str(e):\n        issue = None  # or refetch raw / alert on proxy health\n    else:\n        raise","preventionTips":["Pin and monitor the proxy version alongside the client; upgrade them together.","Add a proxy health check that validates a known issue returns a dict-shaped payload.","Log raw proxy bodies on 5xx so malformed payloads are diagnosable.","Wrap proxy-backed reads in a small retry for transient gateway corruption."],"tags":["proxy","api-contract","payload-validation","github"],"backgroundTag":"proxy-malformed-payload","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}