{"record":{"id":"72d20f37fc181ce2","repo":"can1357/oh-my-pi","slug":"invalid-github-release-metadata","errorCode":null,"errorMessage":"Invalid GitHub release metadata","messagePattern":"Invalid GitHub release metadata","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/update-cli.ts","lineNumber":197,"sourceCode":"\treturn majorVersion(release.version) > majorVersion(currentVersion);\n}\n\n/**\n * Select and validate the binary asset from GitHub release metadata.\n *\n * Draft releases are always rejected. Prereleases are rejected unless\n * `options.allowPrerelease` is set, which the canary channel passes: canary\n * GitHub releases are published as prereleases, and the exact-tag match below\n * still pins the download to the specific requested version.\n */\nexport function resolveReleaseBinaryAsset(\n\trelease: unknown,\n\texpectedTag: string,\n\tbinaryName: string,\n\toptions: { allowPrerelease?: boolean } = {},\n): ReleaseBinaryAsset {\n\tif (!isRecord(release)) {\n\t\tthrow new Error(\"Invalid GitHub release metadata\");\n\t}\n\tif (release.tag_name !== expectedTag) {\n\t\tthrow new Error(`GitHub release tag mismatch: expected ${expectedTag}`);\n\t}\n\tif (release.draft !== false) {\n\t\tthrow new Error(`GitHub release ${expectedTag} is a draft, not a published release`);\n\t}\n\tif (release.prerelease !== false && !options.allowPrerelease) {\n\t\tthrow new Error(`GitHub release ${expectedTag} is a prerelease; only canary updates install prerelease assets`);\n\t}\n\tif (!Array.isArray(release.assets)) {\n\t\tthrow new Error(`GitHub release ${expectedTag} has no asset list`);\n\t}\n\n\tconst matches = release.assets.filter(asset => isRecord(asset) && asset.name === binaryName);\n\tif (matches.length !== 1) {\n\t\tthrow new Error(`GitHub release ${expectedTag} has ${matches.length} assets named ${binaryName}`);\n\t}","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/update-cli.ts#L179-L215","documentation":"During a binary update, resolveReleaseBinaryAsset validates the GitHub API release payload before selecting a download asset. If the response is not a plain object (isRecord fails) it throws this error. This guards against API errors, proxies returning HTML/error bodies, or unexpected payload shapes being treated as release metadata.","triggerScenarios":"GitHub API returning a non-JSON or non-object body (rate-limit JSON parsed elsewhere, proxy/HTML error page, network middleware), a schema change in the releases endpoint, or a cached/garbage response handed to the resolver.","commonSituations":"Corporate proxy intercepting api.github.com; GitHub rate limiting (403 body shapes); running the updater behind a mirror that does not faithfully proxy the API; temporary GitHub incidents.","solutions":["Check connectivity to api.github.com and any proxy configuration (HTTP_PROXY/HTTPS_PROXY).","Wait for GitHub rate limits to reset (check `gh api rate_limit` or response headers) and retry the update.","Retry later if GitHub status shows an incident.","Verify the updater is pointed at the correct repository/releases endpoint; update manually by downloading the release binary from github.com releases as a fallback."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"const res = await fetch(releaseApiUrl, { headers: { accept: \"application/vnd.github+json\" } });\nconst release = await res.json();\nif (typeof release !== \"object\" || release === null || Array.isArray(release) || typeof release.tag_name !== \"string\") {\n  throw new Error(\"Release endpoint returned non-object payload; check proxy/rate limits\");\n}","typeGuard":"function isRelease(v: unknown): v is { tag_name: string; draft: boolean; prerelease: boolean; assets: unknown[] } {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v)\n    && typeof (v as any).tag_name === \"string\"\n    && typeof (v as any).draft === \"boolean\"\n    && typeof (v as any).prerelease === \"boolean\";\n}","tryCatchPattern":"try {\n  const asset = resolveReleaseBinaryAsset(release, expectedTag, binaryName);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Invalid GitHub release metadata\") {\n    console.error(\"GitHub API payload was not a release object — check proxy/rate limit/status.\");\n  }\n  throw err;\n}","preventionTips":["Authenticate GitHub API calls to raise rate limits (GITHUB_TOKEN).","Bypass HTML-injecting corporate proxies for api.github.com.","Check https://www.githubstatus.com before release-day updates.","Validate the payload shape yourself before handing it to the resolver."],"tags":["github","update","api","validation"],"backgroundTag":"invalid-api-response","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}