{"record":{"id":"902948e9184deebf","repo":"Hmbown/CodeWhale","slug":"label-returned-http-status-url","errorCode":null,"errorMessage":"${label} returned HTTP ${status} (${url})","messagePattern":"(.+?) returned HTTP (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"npm/codewhale/scripts/verify-release-assets.js","lineNumber":102,"sourceCode":"          const next = new URL(location, url).toString();\n          resolve(requestStatus(next, method, redirects + 1));\n          return;\n        }\n        resolve(status);\n      },\n    );\n    req.on(\"error\", reject);\n    req.end();\n  });\n}\n\nasync function verifyAsset(url, label) {\n  let status = await requestStatus(url, \"HEAD\");\n  if (status === 403 || status === 405) {\n    status = await requestStatus(url, \"GET\");\n  }\n  if (status < 200 || status >= 400) {\n    throw new Error(`${label} returned HTTP ${status} (${url})`);\n  }\n}\n\nasync function downloadText(url, redirects = 0) {\n  if (redirects > 10) {\n    throw new Error(`Too many redirects while downloading ${url}`);\n  }\n  const client = url.startsWith(\"https:\") ? https : http;\n  return new Promise((resolve, reject) => {\n    client\n      .get(\n        url,\n        {\n          headers: {\n            \"User-Agent\": \"codewhale-npm-release-check\",\n          },\n        },\n        (res) => {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/npm/codewhale/scripts/verify-release-assets.js#L84-L120","documentation":"verifyAsset checks a release asset URL responds successfully. After trying HEAD (falling back to GET on 403/405), any status outside 2xx/3xx means the asset is missing, private, or the release is broken, so it throws with the label and URL.","triggerScenarios":"run() calls verifyAsset for each expected release asset (checksums, binaries) and the server returns e.g. 404 (asset not uploaded), 401 (private repo), or 5xx.","commonSituations":"Release published before assets finished uploading; tag exists but release is draft; asset renamed so the expected URL 404s; token missing for private repo.","solutions":["Confirm the GitHub release exists, is published (not draft), and all assets are uploaded","Check the asset naming/URL matches what the script expects for this version/arch","Ensure GITHUB_TOKEN is set if the repo is private","Re-upload missing assets or re-run the release workflow"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const res = await fetch(url, { method: \"HEAD\" });\nif (!(res.status >= 200 && res.status < 400)) {\n  throw new Error(`Asset unavailable: ${url} -> ${res.status}; check the release is published with assets uploaded`);\n}","typeGuard":null,"tryCatchPattern":"try { await verifyAsset(url, label); } catch (e) { if (/returned HTTP (404|403)/.test(e.message)) { console.error(\"Release draft or assets missing; re-run release upload\"); } throw e; }","preventionTips":["Publish releases only after all assets finish uploading","Verify asset names/URL templates per version and arch","Set a token for private repos"],"tags":["http","release","github","assets"],"backgroundTag":"http-error-response","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}