{"record":{"id":"7ef011f7a536ae4c","repo":"stablyai/orca","slug":"github-releases-response-for-repo-was-not-an-ar","errorCode":null,"errorMessage":"GitHub releases response for ${repo} was not an array","messagePattern":"GitHub releases response for (.+?) was not an array","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/scripts/publish-complete-draft-releases.mjs","lineNumber":71,"sourceCode":"      'X-GitHub-Api-Version': API_VERSION,\n      ...options.headers\n    }\n  })\n  if (!res.ok) {\n    const body = await res.text().catch(() => '')\n    throw new Error(`GitHub request failed ${res.status} ${res.statusText}: ${body.slice(0, 300)}`)\n  }\n  return res.json()\n}\n\nasync function fetchReleases(repo, token, fetchImpl) {\n  const releases = await githubJson(\n    fetchImpl,\n    `https://api.github.com/repos/${repo}/releases?per_page=100`,\n    token\n  )\n  if (!Array.isArray(releases)) {\n    throw new Error(`GitHub releases response for ${repo} was not an array`)\n  }\n  return releases\n}\n\nexport async function publishCompleteDraftReleases({\n  repo,\n  token,\n  fetchImpl = fetch,\n  verifyReleaseAssets = verifyRequiredReleaseAssets,\n  isDraftBuiltFromCurrentRef = ({ tag }) => isTagBuiltFromCurrentRef(tag),\n  log = console.log\n}) {\n  if (!repo) {\n    throw new Error('repo is required')\n  }\n  if (!token) {\n    throw new Error('token is required')\n  }","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/publish-complete-draft-releases.mjs#L53-L89","documentation":"Thrown by fetchReleases in config/scripts/publish-complete-draft-releases.mjs when the GitHub `/repos/{repo}/releases` endpoint returns an HTTP-OK response whose JSON body is not an Array. The releases endpoint is contractually an array, so a non-array (an error object, a single release object, or a proxy-intercepted shape) signals a corrupted or redirected response that the rest of the pipeline cannot filter or sort.","triggerScenarios":"GitHub returns 200 with a non-array body — rare but possible behind a corporate proxy that swaps in an HTML/error JSON object, or if the API contract changes and a future endpoint returns a paginated envelope object. The check at line 70-71 fires immediately after githubJson succeeds.","commonSituations":"A transparent proxy or npm-registry mirror rewrites the GitHub response, a test fetchImpl stub returns a hand-crafted object instead of an array, or an API-version mismatch (the script pins X-GitHub-Api-Version to 2022-11-28) returns a different envelope on a future API revision.","solutions":["Confirm the response came from api.github.com and was not intercepted (check the body slice from a reproduced request).","If a proxy is in play, bypass it for api.github.com or fix the stub to return an array.","Verify X-GitHub-Api-Version 2022-11-28 still matches the live API contract for the releases listing."],"exampleFix":"// before\nconst releases = await githubJson(fetchImpl, url, token)\n// releases consumed directly as an array\n\n// after\nconst releases = await githubJson(fetchImpl, url, token)\nif (!Array.isArray(releases)) {\n  throw new Error(`Unexpected releases payload for ${repo}: ${JSON.stringify(releases).slice(0, 200)}`)\n}","handlingStrategy":"validation","validationCode":"const releases = await githubJson(fetchImpl, url, token)\nif (!Array.isArray(releases)) {\n  throw new Error(`Unexpected releases payload for ${repo}: ${JSON.stringify(releases).slice(0, 200)}`)\n}\nreturn releases","typeGuard":"function isReleaseArray(res) {\n  return Array.isArray(res) && res.every((r) => r && typeof r.tag_name === 'string')\n}","tryCatchPattern":null,"preventionTips":["If behind a proxy, bypass it for api.github.com so the array contract holds.","When stubbing fetchImpl in tests, always return an array of release objects.","Pin X-GitHub-Api-Version and re-verify the contract when upgrading the API version."],"tags":["github","api","release","response-validation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}