Hmbown/CodeWhale · error · Error
envelope does not verify
Error message
envelope does not verify: ${check.errors.join("; ")} What it means
After finding the pinned active key, activePublishingKey calls verifyEnvelope(envelope, key.publicKey) and refuses publication when the cryptographic check fails, surfacing verifyEnvelope's error list joined by "; ". This means the Ed25519 signature, canonical payload encoding, or envelope fields did not validate against the pinned public key.
Solutions
- Read the check.errors list in the message to identify the exact failing verification (signature mismatch, bad encoding, missing field) and fix that specifically
- Re-sign the current payload with the private key corresponding to the pinned active key_id, then retry with the fresh envelope
- Verify the envelope bytes were not altered between signing and publishing (no editor formatting, re-encoding, or newline changes to payload_b64/signature)
Defensive patterns
Strategy: validation
Validate before calling
const check = verifyEnvelope(envelope, pinnedPublicKey);
if (!check.ok) {
console.error("envelope will be rejected:", check.errors);
throw new Error("re-sign the current payload with the pinned key before publishing");
} Try / catch
try {
await activePublishingKey(envelope, keys);
} catch (err) {
if (err.message.startsWith("envelope does not verify:")) {
console.error("Signature/payload verification failed:", err.message.slice("envelope does not verify: ".length));
process.exit(1);
}
throw err;
} Prevention
- Never modify payload fields after signing; regenerate the signature whenever the payload changes
- Verify envelopes locally with verifyEnvelope before attempting publication
- Ensure payload_b64/signature survive transport unchanged (no line wrapping, whitespace edits, or re-encoding)
When it happens
Trigger: Calling activePublishingKey with an envelope whose payload was modified after signing, signed with a different private key than the pinned public key, with a corrupted payload_b64/signature, or with fields failing verifyEnvelope's structural checks (the specific reasons appear in check.errors).
Common situations: The payload JSON was regenerated (timestamps changed) without re-signing; the envelope was built with a dev key but published against production keys; base64 payloads were mangled by copy/paste or line wrapping.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/ceb7c0f74c4a7c75.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/facts-publish.mjs:407
const keys = [];
const remainder = body.replace(/\{\s*keyId:\s*"([^"]+)",\s*publicKey:\s*"([^"]+)",\s*status:\s*"([^"]+)"\s*,?\s*\}/g, (_, keyId, publicKey, status) => {
keys.push({ keyId, publicKey, status });
return "";
});
if (remainder.replace(/[\s,]/g, "")) throw new Error("unparsed TypeScript TRUSTED_KEYS entry");
return validateTrustedKeys(keys);
}
function loadTrustedKeysFromRepo() {
const keys = parseTsKeys(readBoundedFile(resolve(WEB_ROOT, "lib/cloud-facts/keys.ts"), 64 * 1024).toString("utf8"));
return new Map(keys.map((key) => [key.keyId, key]));
}
export function activePublishingKey(envelope, keys, now = Date.now()) {
const key = validateTrustedKeys(keys).find((key) => key.keyId === envelope.key_id && key.status === "active");
if (!key) throw new Error("primary signing key is not pinned and active; refusing publication");
const check = verifyEnvelope(envelope, key.publicKey);
if (!check.ok) throw new Error(`envelope does not verify: ${check.errors.join("; ")}`);
if (!Number.isFinite(now) || utcTime(check.payload.published_at) > now + 300_000 ||
(check.payload.not_after != null && utcTime(check.payload.not_after) <= now)) throw new Error("publication timestamp is future or expired");
return { key, check };
}
function refuseUnderCi() {
for (const marker of CI_MARKERS) {
if (process.env[marker] && !/^(0|false|no|off)$/i.test(process.env[marker])) {
throw new Error(`refusing to run with a secret under CI (${marker} is set); publish from the founder's machine`);
}
}
}
function sqlLiteral(value) {
if (value === null || value === undefined) return "null";
return `'${String(value).replace(/'/g, "''")}'`;
}
View on GitHub (pinned to 433685b202)