{"record":{"id":"aecd62c308c613e4","repo":"JuliusBrussee/caveman","slug":"binary-download-failed-error-message","errorCode":null,"errorMessage":"binary download failed: ${error.message}","messagePattern":"binary download failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/shared/binary-installer/installer.mjs","lineNumber":92,"sourceCode":"export function binaryInstallFilename(name, os = process.platform) {\n  return os === \"win32\" ? `${name}.exe` : name;\n}\n\nfunction timeoutMs() {\n  const raw = process.env.CAVE_SETUP_TIMEOUT ?? \"300\";\n  const seconds = Number(raw);\n  if (!Number.isInteger(seconds) || seconds <= 0) {\n    throw new Error(`CAVE_SETUP_TIMEOUT must be a positive integer (got ${JSON.stringify(raw)})`);\n  }\n  return seconds * 1000;\n}\n\nasync function asset(url, timeout) {\n  let response;\n  try {\n    response = await fetch(url, { signal: AbortSignal.timeout(timeout) });\n  } catch (error) {\n    throw new Error(`binary download failed: ${error.message}`);\n  }\n  if (!response.ok) throw new Error(`binary download failed: HTTP ${response.status}`);\n  return response;\n}\n\nfunction signedDigest(checksums, bundleRaw) {\n  try {\n    const bundle = JSON.parse(bundleRaw);\n    if (bundle.mediaType !== \"application/vnd.dev.sigstore.bundle.v0.3+json\") return false;\n    if (bundle.messageSignature?.messageDigest?.algorithm !== \"SHA2_256\") return false;\n    const digest = createHash(\"sha256\").update(checksums).digest();\n    const bundled = Buffer.from(bundle.messageSignature.messageDigest.digest, \"base64\");\n    if (digest.length !== bundled.length || !digest.equals(bundled)) return false;\n    return verify(\n      \"sha256\",\n      Buffer.from(checksums),\n      createPublicKey(BINARY_SIGNING_PUBKEY),\n      Buffer.from(bundle.messageSignature.signature, \"base64\"),","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/shared/binary-installer/installer.mjs#L74-L110","documentation":"asset() in the binary installer wraps fetch() with AbortSignal.timeout; any thrown error (DNS failure, connection refused, TLS problem, or the abort timeout firing) is rethrown as 'binary download failed: <cause>'. The message preserves the underlying error text for diagnosis.","triggerScenarios":"Offline machine, blocked DNS, firewall or egress rules denying the release host, a corporate proxy not honored by undici fetch, or a slow link exceeding CAVE_SETUP_TIMEOUT (abort/TimeoutError appears in the message).","commonSituations":"CI runners without internet egress; air-gapped environments; HTTPS_PROXY set but undici ignoring it; slow links timing out at the default 300 seconds.","solutions":["If the message mentions abort or timeout, raise CAVE_SETUP_TIMEOUT (for example 600) and retry","Verify network reachability of the release base URL from that machine (curl the same URL)","For proxies, configure one that global fetch honors (undici EnvHttpProxyAgent or NODE_USE_ENV_PROXY=1), or run the install where egress is open","Pre-install the binary on a connected machine and point CAVEMAN_MCP_BIN / CAVEMAN_SHRINK_BIN / CAVEMAN_BROWSE_BIN at it"],"exampleFix":"# before\nCAVE_SETUP_TIMEOUT=30 npm run setup   # 'binary download failed: TimeoutError: The operation was aborted'\n\n# after\nCAVE_SETUP_TIMEOUT=600 npm run setup","handlingStrategy":"retry","validationCode":"// probe reachability before setup\nawait fetch(releaseBase, { signal: AbortSignal.timeout(5000) })\n  .catch(() => { throw new Error(\"release host unreachable — check egress/proxy\"); });","typeGuard":null,"tryCatchPattern":"for (const wait of [0, 2000, 8000]) {\n  await sleep(wait);\n  try { return await ensureBinary({ name, envVar }); }\n  catch (e) {\n    if (!/^binary download failed: /.test(String(e?.message)) || /HTTP \\d+/.test(e.message)) throw e;\n  }\n}\n// retry transport failures only; HTTP-status failures are not retried blindly","preventionTips":["Pre-provision binaries in CI images and point CAVEMAN_*_BIN at them","Size CAVE_SETUP_TIMEOUT to your link speed","Ensure global fetch honors your proxy in Node (undici EnvHttpProxyAgent or NODE_USE_ENV_PROXY=1)"],"tags":["network","installer","timeout"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}