can1357/oh-my-pi · error · GitHubError

proxy returned malformed release payload

Error message

proxy returned malformed release payload

What it means

`_release_from` converts a release object from the gh-proxy into `ReleaseInfo`. If the value returned for a release is not a JSON object, the client raises `GitHubError(500, ...)` with this message instead of failing later on field access. It indicates the proxy violated the expected release payload shape.

Solutions

  1. Capture and inspect the raw response body from the proxy for get_release_by_tag
  2. Bring proxy and client library versions into agreement on the release schema
  3. Confirm the request reaches the real gh-proxy service, not an error page from an intermediary

Example fix

# before
release = client.get_release_by_tag(repo, tag)
# after
try:
    release = client.get_release_by_tag(repo, tag)
except GitHubError as e:
    if "malformed release payload" in str(e):
        release = None  # fall back to manual tag handling
    else:
        raise
Defensive patterns

Strategy: type-guard

Validate before calling

release_payload = fetch_raw_release(repo, tag)
if not isinstance(release_payload, dict):
    raise ValueError(f"proxy release payload is {type(release_payload).__name__}, expected object")

Type guard

def is_release_payload(v: object) -> TypeGuard[dict]:
    return isinstance(v, dict) and "tag" in v

Try / catch

try:
    release = client.get_release_by_tag(repo, tag)
except GitHubError as e:
    if "malformed release payload" in str(e):
        log.warning("release schema mismatch", extra={"repo": repo, "tag": tag})
        release = None
    else:
        raise

Prevention

When it happens

Trigger: `get_release_by_tag` receiving a non-dict for the release — e.g. the proxy returned `null`/a string when the release lookup result shape differs, or an intermediary error body was parsed as the release.

Common situations: Proxy/client version skew after a release-schema change, custom proxy returning plain tag strings, gateway error pages, or a forked proxy with a different contract.

Understand the failure class

Related errors


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

Appendix: source

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


def _workflow_job_from(data: Any) -> WorkflowJobInfo:
    if not isinstance(data, dict):
        raise GitHubError(500, "proxy returned malformed workflow job payload")
    return WorkflowJobInfo(
        id=int(data.get("id") or 0),
        run_id=int(data.get("run_id") or 0),
        name=str(data.get("name") or ""),
        status=str(data.get("status") or ""),
        conclusion=str(data["conclusion"]) if data.get("conclusion") is not None else None,
        html_url=str(data.get("html_url") or ""),
        failed_steps=tuple(str(step) for step in data.get("failed_steps") or []),
    )


def _release_from(data: Any) -> ReleaseInfo:
    if not isinstance(data, dict):
        raise GitHubError(500, "proxy returned malformed release payload")
    name = data.get("name")
    return ReleaseInfo(
        tag=str(data.get("tag") or ""),
        name=str(name) if name is not None else None,
        draft=bool(data.get("draft")),
        prerelease=bool(data.get("prerelease")),
        html_url=str(data.get("html_url") or ""),
        asset_names=tuple(str(asset) for asset in data.get("asset_names") or []),
    )


def _repo_from(data: Any) -> RepoInfo:
    if not isinstance(data, dict):
        raise GitHubError(500, "proxy returned malformed repo payload")
    return RepoInfo(
        full_name=str(data["full_name"]),
        default_branch=str(data["default_branch"]),
        clone_url=str(data["clone_url"]),

View on GitHub (pinned to 9690622007)