JuliusBrussee/caveman · error

\nfix

Error message

${OFF_STATES.downloadStalled(timeoutSeconds).line}\nfix: ${OFF_STATES.downloadStalled(timeoutSeconds).fix}

What it means

setupInstallFailure translates binary download failures into user-facing errors. A BinaryDownloadError with kind 'stalled' (progress stopped mid-download) throws the downloadStalled off-state line plus its fix; any other download failure throws the generic downloadUnreachable line plus fix.

Solutions

  1. Retry the install command — stalls are often transient network issues.
  2. Check proxy/firewall settings and ensure the release CDN host is reachable (curl the download URL).
  3. Increase the stall/timeout budget via the relevant timeout env (e.g. CAVE_SETUP_TIMEOUT) on slow connections.
  4. Switch networks (VPN off/on, different Wi-Fi) or download the binaries manually.

Example fix

// before
$ cave setup   # download stalls behind corporate proxy
Error: download stalled after 30s\nfix: check network...

// after
$ export HTTPS_PROXY=http://proxy.corp:8080
$ cave setup   # download completes
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(downloadUrl, { method: 'HEAD', signal: AbortSignal.timeout(10000) });
if (!res.ok) console.warn(`download host unreachable (${res.status}) before starting setup`);

Try / catch

try {
  await runSetup();
} catch (error) {
  if (error instanceof BinaryDownloadError && error.kind === 'stalled') {
    await retry(runSetup, { attempts: 3, backoffMs: 5000 }); // transient stall
  } else throw error;
}

Prevention

When it happens

Trigger: Binary download stalling: connection freezes with no bytes for the stall timeout, a proxy/firewall throttles the CDN to zero throughput, or the network drops without closing the socket. Any non-stall error (DNS failure, 403/404, TLS error) produces the downloadUnreachable variant.

Common situations: Corporate proxies that accept the connection but stop forwarding data; flaky Wi-Fi mid-install; CI runners with aggressive network timeouts; rate-limited CDN.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/ead49ab25659900c. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/index.ts:2391

  const line = `${name}  ${platform.os}/${platform.arch}  …`;
  if (interactive()) process.stderr.write(line);
  else console.error(line);
}

function installProgressComplete(
  name: string,
  platform: { os: string; arch: string },
  bytes: number,
) {
  const line = `${name}  ${platform.os}/${platform.arch}  ${(bytes / 1_000_000).toFixed(1)} MB  checksum verified`;
  if (interactive()) process.stderr.write(`\r${line}\n`);
  else console.error(line);
}

function setupInstallFailure(error: unknown, timeoutSeconds: number): never {
  if (interactive()) process.stderr.write("\n");
  if (error instanceof BinaryDownloadError && error.kind === "stalled") {
    throw new Error(`${OFF_STATES.downloadStalled(timeoutSeconds).line}\nfix: ${OFF_STATES.downloadStalled(timeoutSeconds).fix}`);
  }
  throw new Error(`${OFF_STATES.downloadUnreachable.line}\nfix: ${OFF_STATES.downloadUnreachable.fix}`);
}

function printInstallResult(
  installed: InstalledBinary[],
  platform: { os: string; arch: string },
  binDir: string,
  json: boolean,
  continuing = false,
) {
  if (json) {
    print({
      release: BINARY_RELEASE,
      platform: `${platform.os}/${platform.arch}`,
      target: binDir,
      binaries: installed,
      next: "caveman claude",

View on GitHub (pinned to 3ee70a1026)