JuliusBrussee/caveman · critical
signed checksum manifest is malformed
Error message
signed checksum manifest is malformed
What it means
expectedDigest() in the binary installer parses the signature-verified checksums.txt line by line against a strict '<64 lowercase hex> <safe filename>' format (two spaces). A line that is present but does not match — bad hash casing or length, tab separator, carriage-return residue, odd filename characters — makes the whole manifest untrustworthy, so parsing aborts even though the signature checked out.
Source
Thrown at packages/shared/binary-installer/installer.mjs:121
const digest = createHash("sha256").update(checksums).digest();
const bundled = Buffer.from(bundle.messageSignature.messageDigest.digest, "base64");
if (digest.length !== bundled.length || !digest.equals(bundled)) return false;
return verify(
"sha256",
Buffer.from(checksums),
createPublicKey(BINARY_SIGNING_PUBKEY),
Buffer.from(bundle.messageSignature.signature, "base64"),
);
} catch {
return false;
}
}
function expectedDigest(checksums, artifact) {
for (const line of checksums.split("\n")) {
if (!line) continue;
const match = line.match(/^([a-f0-9]{64}) ([A-Za-z0-9._-]+)$/);
if (!match) throw new Error("signed checksum manifest is malformed");
if (match[2] === artifact) return match[1];
}
throw new Error(`signed checksum manifest does not contain ${artifact}`);
}
function cleanup(path) {
try {
unlinkSync(path);
} catch (error) {
if (error.code !== "ENOENT") throw error;
}
}
async function download(url, part, timeout) {
const response = await asset(url, timeout);
if (!response.body) throw new Error("binary download failed: response body missing");
const hash = createHash("sha256");
const file = await open(part, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);View on GitHub (pinned to 27d5a3981a)
Solutions
- If you control the release: regenerate checksums.txt with standard sha256sum output (lowercase hex, two spaces, LF endings)
- If consuming: unset CAVE_BINARY_RELEASE_BASE to pull the official manifest, and report the bad mirror or artifact upstream
- Never hand-edit checksums.txt to make parsing pass — the format rejection is a tamper signal
Example fix
# before (malformed: uppercase hex, tab separator) # 0A1B…F caveman-mcp_linux_amd64 # after cd artifacts && sha256sum * > ../checksums.txt # lowercase hex, two spaces
Defensive patterns
Strategy: validation
Validate before calling
// validate a manifest your pipeline produces, before publishing
for (const line of checksums.split("\n")) {
if (line && !/^([a-f0-9]{64}) ([A-Za-z0-9._-]+)$/.test(line)) {
throw new Error(`malformed checksum line: ${JSON.stringify(line)}`);
}
} Type guard
function isValidChecksumLine(line) {
return /^([a-f0-9]{64}) ([A-Za-z0-9._-]+)$/.test(line);
} Try / catch
try { await ensureBinary({ name, envVar }); }
catch (e) {
if (/signed checksum manifest is malformed/.test(String(e?.message))) {
delete process.env.CAVE_BINARY_RELEASE_BASE; // retry against the official host
return ensureBinary({ name, envVar });
}
throw e;
} Prevention
- Generate manifests with plain sha256sum (lowercase hex, two spaces, LF) and never edit them by hand
- Never loosen parsing to get past this error — it is a tamper signal
When it happens
Trigger: A republished or repacked release where checksums.txt was regenerated with a different tool (different sha256sum flags, CRLF line endings, uppercase hex); a mirror rewriting files; a genuinely tampered manifest that happens to carry a valid signature over corrupted content.
Common situations: Internal mirrors that normalize line endings; release pipelines switching checksum tools; manual edits to checksums.txt; partial file truncation.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- signature check failed for ${artifact} — partial download de
- signed checksum manifest does not contain ${artifact}
- signature check failed for checksums.txt — refusing to insta
- cave_mastra_terminal_failure
- cave_harness_incomplete_evidence
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/92a2c96f8a16e30c.
Report an issue: GitHub.