JuliusBrussee/caveman · error

invalid checksum manifest line

Error message

invalid checksum manifest line: ${JSON.stringify(line)}

What it means

parseSignedChecksums parses a sha256sum-style manifest line-by-line, requiring each non-empty line to match exactly '<64 hex chars> <filename>' (two spaces). Any deviating line throws with the offending line JSON-escaped.

Solutions

  1. Regenerate the manifest with sha256sum so lines match '<hash> <name>' with two spaces.
  2. Normalize line endings: dos2unix checksums.txt.
  3. Remove any comment/header lines and verify each hash is exactly 64 lowercase hex characters.

Example fix

// before
SHA256 (cave-linux-amd64) = abc123...

// after
$ sha256sum cave-linux-amd64 > checksums.txt
abc123...<64 hex>  cave-linux-amd64
Defensive patterns

Strategy: validation

Validate before calling

const lineRe = /^[a-f0-9]{64}  [A-Za-z0-9._-]+$/;
for (const line of raw.split('\n')) {
  if (line && !lineRe.test(line)) throw new Error(`malformed manifest line (need '<64-hex>  <name>', LF endings): ${line}`);
}

Try / catch

try {
  verify(manifest);
} catch (error) {
  if (error.message.startsWith('invalid checksum manifest line')) {
    console.error(`${error.message}\nRegenerate with: sha256sum <files> > checksums.txt`);
  } else throw error;
}

Prevention

When it happens

Trigger: Downloading/supplying a checksum manifest with a truncated hash, a single space instead of two, BSD-style 'SHA256 (...)' format, CRLF line endings (the \r makes the filename regex fail), or extra commentary lines.

Common situations: Hand-editing the manifest and breaking the two-space separator; generating the manifest with `shasum -a 256` plus annotations; transferring the file through a tool that added CRLF endings.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

function verifiedLocalInstall(binDir: string): InstalledBinary[] | null {
  const manifest = readBinaryInstallManifest();
  if (!manifest || manifest.release !== BINARY_RELEASE) return null;
  const installed: InstalledBinary[] = [];
  for (const name of INSTALL_BINARIES) {
    const expected = manifest.artifacts[name];
    const path = join(binDir, binaryInstallFilename(name));
    if (!expected || sha256File(path) !== expected) return null;
    installed.push({ name, path, sha256: expected, status: "already installed" });
  }
  return installed;
}

function parseSignedChecksums(raw: string): Map<string, string> {
  const checksums = new Map<string, string>();
  for (const line of raw.split("\n")) {
    if (!line) continue;
    const match = line.match(/^([a-f0-9]{64})  ([A-Za-z0-9._-]+)$/);
    if (!match) throw new Error(`invalid checksum manifest line: ${JSON.stringify(line)}`);
    const filename = match[2]!;
    if (checksums.has(filename)) throw new Error(`duplicate checksum manifest entry: ${filename}`);
    checksums.set(filename, match[1]!);
  }
  return checksums;
}

function verifyChecksumSignature(checksums: string, signature: string): boolean {
  try {
    const bundle = JSON.parse(signature) as {
      mediaType?: unknown;
      messageSignature?: {
        messageDigest?: { algorithm?: unknown; digest?: unknown };
        signature?: unknown;
      };
    };
    if (bundle.mediaType !== "application/vnd.dev.sigstore.bundle.v0.3+json") return false;
    if (bundle.messageSignature?.messageDigest?.algorithm !== "SHA2_256") return false;

View on GitHub (pinned to 3ee70a1026)