{"record":{"id":"96c0e9f7060ebab6","repo":"nextlevelbuilder/ui-ux-pro-max-skill","slug":"failed-to-download-response-status-response","errorCode":null,"errorMessage":"Failed to download: ${response.status} ${response.statusText}","messagePattern":"Failed to download: (.+?) (.+?)","errorType":"http","errorClass":"GitHubDownloadError","httpStatus":null,"severity":"error","filePath":"cli/src/utils/github.ts","lineNumber":106,"sourceCode":"    throw new GitHubDownloadError(`Failed to fetch latest release: ${response.status} ${response.statusText}`);\n  }\n\n  return response.json();\n}\n\nexport async function downloadRelease(url: string, dest: string, token?: string): Promise<void> {\n  const response = await fetch(url, {\n    headers: {\n      'User-Agent': USER_AGENT,\n      'Accept': 'application/octet-stream',\n      ...getAuthHeaders(token),\n    },\n  });\n\n  checkRateLimit(response);\n\n  if (!response.ok) {\n    throw new GitHubDownloadError(`Failed to download: ${response.status} ${response.statusText}`);\n  }\n\n  const buffer = await response.arrayBuffer();\n  await writeFile(dest, Buffer.from(buffer));\n}\n\nexport function getAssetUrl(release: Release): string | null {\n  // First try to find an uploaded ZIP asset\n  const asset = release.assets.find(a => a.name.endsWith('.zip'));\n  if (asset?.browser_download_url) {\n    return asset.browser_download_url;\n  }\n\n  // Fall back to GitHub's auto-generated archive\n  // Format: https://github.com/{owner}/{repo}/archive/refs/tags/{tag}.zip\n  if (release.tag_name) {\n    return `https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/${release.tag_name}.zip`;\n  }","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/blob/a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5/cli/src/utils/github.ts#L88-L124","documentation":"downloadRelease() streams a release asset to disk; after checkRateLimit(), any non-2xx becomes GitHubDownloadError('Failed to download: <status> <reason>'). Because it sends 'Accept: application/octet-stream' plus auth headers to the asset URL, common causes are 404 (asset deleted or URL expired) and 401/403 (token invalid or lacking access to a private asset). The asset URL from the API can also go stale after re-uploading assets.","triggerScenarios":"Calling downloadRelease() with a browser_download_url captured from an older release JSON whose asset was since replaced (404); an invalid token producing 401 on the asset CDN redirect; expired signed S3 URL after GitHub re-uploaded the asset; transient 5xx from the asset CDN.","commonSituations":"Re-using a cached release object instead of re-fetching; tokens with fine-grained permissions that don't cover 'Contents: read' on the repo; asset deleted by retention policy.","solutions":["Re-fetch the release (getLatestRelease) immediately before downloading so the asset URL is fresh, then retry.","Confirm the asset still exists on the release page; if re-uploaded, invalidate any cached release JSON.","Verify the token is valid and has read access to the repo if the asset is private (curl -I the URL with the Bearer header).","For 5xx, retry with backoff; check githubstatus.com."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { downloadRelease, getLatestRelease } from './utils/github';\n\nasync function downloadFresh(dest: string, token?: string) {\n  for (let attempt = 0; attempt < 3; attempt++) {\n    const release = await getLatestRelease(token); // fresh asset URL each try\n    const asset = release.assets.find(a => a.name.endsWith('.zip'));\n    if (!asset) throw new Error('No zip asset on latest release');\n    try {\n      await downloadRelease(asset.browser_download_url, dest, token);\n      return;\n    } catch (e) {\n      if (e instanceof GitHubDownloadError && e.message.includes('404') && attempt < 2) continue;\n      throw e;\n    }\n  }\n}","preventionTips":["Never cache asset URLs for long — re-fetch the release JSON right before download.","Verify the token scope covers Contents:read when assets live on a private repo.","Check downloaded size and magic bytes after download to catch corrupted bodies."],"tags":["github-api","download","http-status","network","assets"],"backgroundTag":null,"analyzedSha":"a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5","analyzedAt":"2026-08-14T18:51:02.321Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}