{"record":{"id":"1fbc8065816d2f35","repo":"can1357/oh-my-pi","slug":"proxy-returned-malformed-workflow-job-payload","errorCode":null,"errorMessage":"proxy returned malformed workflow job payload","messagePattern":"proxy returned malformed workflow job payload","errorType":"exception","errorClass":"GitHubError","httpStatus":500,"severity":"error","filePath":"python/robomp/src/proxy_client.py","lineNumber":568,"sourceCode":"def _workflow_run_from(data: Any) -> WorkflowRunInfo:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed workflow run payload\")\n    return WorkflowRunInfo(\n        id=int(data.get(\"id\") or 0),\n        name=str(data.get(\"name\") or \"\"),\n        event=str(data.get(\"event\") or \"\"),\n        status=str(data.get(\"status\") or \"\"),\n        conclusion=str(data[\"conclusion\"]) if data.get(\"conclusion\") is not None else None,\n        head_branch=str(data[\"head_branch\"]) if data.get(\"head_branch\") is not None else None,\n        head_sha=str(data.get(\"head_sha\") or \"\"),\n        html_url=str(data.get(\"html_url\") or \"\"),\n        run_attempt=int(data.get(\"run_attempt\") or 1),\n    )\n\n\ndef _workflow_job_from(data: Any) -> WorkflowJobInfo:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed workflow job payload\")\n    return WorkflowJobInfo(\n        id=int(data.get(\"id\") or 0),\n        run_id=int(data.get(\"run_id\") or 0),\n        name=str(data.get(\"name\") or \"\"),\n        status=str(data.get(\"status\") or \"\"),\n        conclusion=str(data[\"conclusion\"]) if data.get(\"conclusion\") is not None else None,\n        html_url=str(data.get(\"html_url\") or \"\"),\n        failed_steps=tuple(str(step) for step in data.get(\"failed_steps\") or []),\n    )\n\n\ndef _release_from(data: Any) -> ReleaseInfo:\n    if not isinstance(data, dict):\n        raise GitHubError(500, \"proxy returned malformed release payload\")\n    name = data.get(\"name\")\n    return ReleaseInfo(\n        tag=str(data.get(\"tag\") or \"\"),\n        name=str(name) if name is not None else None,","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy_client.py#L550-L586","documentation":"`_workflow_job_from` maps one workflow-job entry from the gh-proxy response into `WorkflowJobInfo`. If an entry is not a JSON object, the client raises `GitHubError(500, ...)` because it cannot safely read the expected fields. This is a client-side contract-violation error against the proxy's response format.","triggerScenarios":"`list_workflow_jobs` receiving a job list whose elements are strings/numbers/null instead of objects — typically a proxy version skew, an error page parsed as data, or a corrupted/partial response.","commonSituations":"Proxy upgraded to a new job schema while the client library is pinned old (or vice versa), reverse proxy or service mesh injecting error bodies, custom proxy implementations returning different shapes.","solutions":["Log/inspect the raw proxy response to see what the job entries actually look like","Align client and proxy versions (upgrade the robomp client or the proxy)","Bypass intermediaries (gateways, caches) that may replace the response body","If you control the proxy, ensure job list items are always JSON objects"],"exampleFix":"// before\njobs = client.list_workflow_jobs(run_id)  # GitHubError on non-dict entry\n// after\ntry:\n    jobs = client.list_workflow_jobs(run_id)\nexcept GitHubError as e:\n    log.warning(\"proxy job payload malformed\", extra={\"run_id\": run_id, \"err\": str(e)})\n    jobs = []","handlingStrategy":"type-guard","validationCode":"jobs_payload = fetch_raw_jobs(run_id)\nif not isinstance(jobs_payload, list) or not all(isinstance(j, dict) for j in jobs_payload):\n    raise ValueError(\"proxy workflow-jobs payload malformed\")","typeGuard":"def is_job_payload(v: object) -> TypeGuard[dict]:\n    return isinstance(v, dict) and \"id\" in v and \"run_id\" in v","tryCatchPattern":"try:\n    jobs = client.list_workflow_jobs(run_id)\nexcept GitHubError as e:\n    if \"malformed workflow job payload\" in str(e):\n        log.warning(\"proxy job schema mismatch\", extra={\"run_id\": run_id})\n        jobs = []\n    else:\n        raise","preventionTips":["Version-align client and proxy deployments","Add CI checks that parse real proxy fixtures with the client mappers","Reject proxy error bodies at the transport layer before mapping","Pin the proxy version in client integration tests"],"tags":["proxy","contract-mismatch","parsing","client-error"],"backgroundTag":"proxy-payload-schema-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}