{"record":{"id":"37466966fb4d6abf","repo":"ruvnet/ruflo","slug":"release-download-failed-http-response-status-f","errorCode":null,"errorMessage":"release download failed: HTTP ${response.status} for ${url}","messagePattern":"release download failed: HTTP (.+?) for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/proxy/release.ts","lineNumber":65,"sourceCode":"  return `meta-proxy-${version}-${triple}.${releaseArchiveExtension(triple)}`;\n}\n\nexport interface ReleaseAssets {\n  archiveBytes: Buffer;\n  archiveFilename: string;\n  sumsBytes: Buffer;\n  sigBase64: string;\n}\n\nconst DEV_INSTALL_ENV = 'RUFLO_DEV_PROXY_INSTALL';\nconst RELEASE_SOURCE_ENV = 'RUFLO_PROXY_RELEASE_SOURCE';\nconst GH_REPO = 'cognitum-one/meta-proxy';\nconst PUBLIC_DIST_BASE = 'https://github.com/cognitum-one/meta-proxy-dist/releases/download';\nconst MAX_ARCHIVE_BYTES = 32 * 1024 * 1024;\n\nasync function downloadPublicAsset(url: string, maxBytes: number): Promise<Buffer> {\n  const response = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(120_000) });\n  if (!response.ok) throw new Error(`release download failed: HTTP ${response.status} for ${url}`);\n  const declared = Number(response.headers.get('content-length') ?? 0);\n  if (declared > maxBytes) throw new Error(`release asset exceeds ${maxBytes} byte limit`);\n  const bytes = Buffer.from(await response.arrayBuffer());\n  if (bytes.length > maxBytes) throw new Error(`release asset exceeds ${maxBytes} byte limit`);\n  return bytes;\n}\n\nasync function ghExecutor() {\n  // Dynamic import, not a static one: @claude-flow/security is only an\n  // optionalDependency of this package (see auth/security-bridge.ts for the\n  // same reasoning) — a static top-level import would crash module load for\n  // any consumer that doesn't have it installed, even ones that never touch\n  // this dev-only download path.\n  const { SafeExecutor } = await import('@claude-flow/security');\n  return new SafeExecutor({ allowedCommands: ['gh'], timeout: 120_000 });\n}\n\n/**","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/proxy/release.ts#L47-L83","documentation":"downloadPublicAsset() fetches a release asset from the meta-proxy-dist GitHub releases URL with redirect-following and a 120-second timeout; any non-OK status aborts the install with the HTTP code and full URL. This is the default public download path, distinct from the gh-CLI dev path.","triggerScenarios":"HTTP 404 — the version tag or asset filename does not exist (deleted/unpublished release, wrong pinned version); 403 — GitHub rate limiting or a blocking corporate proxy; 5xx — transient GitHub/CDN failure. All surface through this single message with the status embedded.","commonSituations":"Pinning a version tag that was later removed; corporate egress proxies answering 403/502 for github.com; rate limits from shared CI IPs; wrong RUFLO_PROXY_RELEASE_SOURCE override values.","solutions":["Open the URL shown in the message — if 404, verify the tag exists on the cognitum-one/meta-proxy-dist releases page and that your ruflo version requests a published one","Retry after a short wait for transient 5xx/proxy failures","Behind corporate proxies, set HTTPS_PROXY/HTTP_PROXY so fetch can traverse them","Update ruflo — version/asset naming changes are fixed in newer releases"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight the release URL cheaply before scripting installs\nconst res = await fetch(`${distBase}/${tag}/${assetName}`, { method: 'HEAD' });\nif (!res.ok) throw new Error(`release not reachable: HTTP ${res.status}`);","typeGuard":"const isHttpDownloadFailure = (e: unknown): e is Error =>\n  e instanceof Error && /^release download failed: HTTP \\d+/.test(e.message);","tryCatchPattern":"for (let i = 1; ; i++) {\n  try {\n    return await downloadPublicAsset(url, MAX_BYTES);\n  } catch (e) {\n    const status = isHttpDownloadFailure(e) ? Number(/HTTP (\\d+)/.exec(e.message)?.[1]) : 0;\n    if (status === 404 || (status && status < 500)) throw e;   // permanent — do not retry\n    if (i >= 3) throw e;                                       // transient exhausted\n    await new Promise(r => setTimeout(r, 2 ** i * 500));       // 5xx/network → backoff\n  }\n}","preventionTips":["Verify the release tag exists on the dist repo before scripting installs","Set HTTPS_PROXY explicitly in corporate networks","Distinguish 404/403 (permanent) from 5xx (transient) when adding retries","Pin versions confirmed to be published"],"tags":["network","download","github-releases","http-status","proxy-install"],"backgroundTag":"http-download-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}