JuliusBrussee/caveman · critical · Error

signature check failed for ${artifact} — partial download de

Error message

signature check failed for ${artifact} — partial download deleted

What it means

After streaming the platform artifact to a .part file and hashing it incrementally, ensureBinary() compares the computed SHA-256 against the entry in the signature-verified checksums.txt. A mismatch means the bytes received are not the bytes signed — corrupted, truncated, or altered in transit — so the partial download is deleted and the install aborted.

Source

Thrown at packages/shared/binary-installer/installer.mjs:186

  const artifact = `${name}_${os}_${arch}`;
  const base = (process.env.CAVE_BINARY_RELEASE_BASE ?? BINARY_RELEASE_BASE_DEFAULT).replace(/\/+$/, "");
  const release = `${base}/${BINARY_RELEASE}`;
  const timeout = timeoutMs();
  const [checksumsResponse, signatureResponse] = await Promise.all([
    asset(`${release}/checksums.txt`, timeout),
    asset(`${release}/checksums.txt.keysig`, timeout),
  ]);
  const [checksums, signature] = await Promise.all([checksumsResponse.text(), signatureResponse.text()]);
  if (!signedDigest(checksums, signature)) {
    throw new Error("signature check failed for checksums.txt — refusing to install");
  }
  const expected = expectedDigest(checksums, artifact);
  mkdirSync(binDir, { recursive: true });
  const part = `${target}.part`;
  cleanup(part);
  try {
    const actual = await download(`${release}/${artifact}`, part, timeout);
    if (actual !== expected) throw new Error(`signature check failed for ${artifact} — partial download deleted`);
    chmodSync(part, 0o755);
    renameSync(part, target);
  } catch (error) {
    cleanup(part);
    throw error;
  }
  process.stderr.write(`${name}  ${os}/${arch}  checksum verified\n`);
  return target;
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Free disk space and retry the install — the .part file is auto-cleaned, so a plain rerun is safe
  2. If a proxy or AV middleware is on the path, bypass it for the release host or add an exception, then retry
  3. Verify by hashing manually: download the artifact with curl, run sha256sum, compare to checksums.txt — a persistent mismatch means a bad mirror or host, not your network
  4. Self-supply a trusted binary via CAVEMAN_MCP_BIN / CAVEMAN_SHRINK_BIN / CAVEMAN_BROWSE_BIN if the host cannot be fixed

Example fix

# before (flaky proxy mangles the body)
npm run setup   # signature check failed … partial download deleted

# after
export NO_PROXY=release.host.example   # or fix the proxy exception
npm run setup
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight disk space so the streamed write cannot come up short
const st = await fs.promises.statfs(binDir);
if (st.bsize * st.bavail < 100 * 1024 * 1024) {
  throw new Error("insufficient disk space for binary install");
}

Try / catch

for (const wait of [0, 3000, 10000]) {
  await sleep(wait);
  try { return await ensureBinary({ name, envVar }); }
  catch (e) {
    if (!/signature check failed for .* — partial download deleted/.test(String(e?.message))) throw e;
  }
}
// corrupted-truncation failures are safe to retry — the .part file is always cleaned

Prevention

When it happens

Trigger: Truncated download (connection dropped mid-stream without fetch erroring); proxies or antivirus rewriting bodies; disk-full producing a short file; bit-level corruption on flaky links; a mirror serving a different build under the same name.

Common situations: Corporate TLS-inspecting proxies altering payloads; antivirus injecting bytes; CI runners with flaky egress; disk quota exhaustion mid-write; slow links where partial flushes survive.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/e0974b2c6619f649. Report an issue: GitHub.