Hmbown/CodeWhale · error · Error
key is not pinned and active; use --public-key only for…
Error message
key is not pinned and active; use --public-key only for explicit offline verification
What it means
The verify subcommand normally loads the trusted key for envelope.key_id from the repo-pinned trust table (loadTrustedKeysFromRepo) and requires its status to be "active". If the key_id is unknown, unpinned, or not active (e.g. revoked), verification is refused with this message; --public-key is the explicit opt-in for offline verification against an ad-hoc key.
Solutions
- If you explicitly trust the key, pass --public-key <pem|base64> for offline verification
- Add/activate the key in the repo's pinned trusted-keys table and retry
- Check envelope.key_id for typos against the pinned table entries
- Re-sign with the currently active publishing key
Example fix
// before node facts-publish.mjs verify envelope.json // after node facts-publish.mjs verify envelope.json --public-key ~/.secrets/cwf-prod.public.pem
Defensive patterns
Strategy: validation
Validate before calling
const trusted = loadTrustedKeysFromRepo().get(envelope.key_id);
if (!(trusted && trusted.status === 'active') && !flags['public-key']) {
throw new Error(`key ${envelope.key_id} is not pinned and active; pass --public-key for offline verify`);
} Try / catch
const exit = await run(['verify', envelopePath]).catch((e) => {
if (e.message.includes('not pinned and active')) {
// fall back to explicit offline verification
return run(['verify', envelopePath, '--public-key', pubPem]);
}
throw e;
}); Prevention
- Pin and activate every publishing key in the repo trust table before signing envelopes
- Complete key rotations (new key active) before distributing envelopes
- Check envelope.key_id against the pinned table when verification fails
When it happens
Trigger: Verifying an envelope signed with a key never added to the repo trust table; a key whose status in the pinned table is "revoked" or "pending"; a typo'd or rotated key_id in the envelope; verifying before the key-rotation SQL was applied to the repo.
Common situations: Rotating publishing keys and forgetting to commit the new key pin; verifying an old envelope after its key was revoked; receiving an envelope from another fork whose pinned key set differs.
Related errors
- --public-key is only for offline verify/emit-sql…
- agent profile may not request trust=true
- bad channel slug
- Codewhale successful run contained an error event
- Codewhale terminal receipt did not confirm auto tools
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/432bf1d92e237ae3.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/facts-publish.mjs:556
if (!Number.isSafeInteger(factsVersion) || factsVersion <= 0) throw new Error("--facts-version (or source.facts_version) must be a positive integer");
const keyId = String(flags["key-id"] ?? "");
const privateKey = loadPrivateKeyFromEnv();
const publishedAt = String(flags["published-at"] ?? nowIso());
const payload = buildPayload(source, { channel, factsVersion, publishedAt });
const envelope = buildEnvelope({ privateKey, keyId, payload });
const text = `${JSON.stringify(envelope, null, 2)}\n`;
if (flags.out) {
writeFileSync(resolve(String(flags.out)), text);
console.error(`wrote ${flags.out} (channel=${channel} facts_version=${factsVersion} key_id=${keyId} sha256=${envelope.sha256})`);
} else process.stdout.write(text);
return 0;
}
if (cmd === "verify") {
const envelope = readJson(resolve(String(positional[1] ?? "")));
let pub = flags["public-key"];
if (!pub) {
const trusted = loadTrustedKeysFromRepo().get(envelope.key_id);
if (!trusted || trusted.status !== "active") throw new Error("key is not pinned and active; use --public-key only for explicit offline verification");
pub = trusted.publicKey;
}
const result = verifyEnvelope(envelope, String(pub));
console.log(JSON.stringify({ ok: result.ok, errors: result.errors, channel: envelope.channel, facts_version: envelope.facts_version, key_id: envelope.key_id, sha256: result.sha256 ?? null }, null, 2));
return result.ok ? 0 : 1;
}
if (cmd === "emit-sql") {
const envelope = readJson(resolve(String(positional[1] ?? "")));
let pub = flags["public-key"];
if (!pub) pub = activePublishingKey(envelope, [...loadTrustedKeysFromRepo().values()]).key.publicKey;
process.stdout.write(emitSql(envelope, { publishedBy: String(flags["published-by"] ?? ""), publicKeyB64: pub ? String(pub) : undefined, notes: String(flags.notes ?? "") }));
return 0;
}
if (cmd === "publish") {
const envelope = readJson(resolve(String(positional[1] ?? "")));
if (flags["public-key"] !== undefined) throw new Error("--public-key is only for offline verify/emit-sql; publication requires the active pinned table");
const { key, check } = activePublishingKey(envelope, [...loadTrustedKeysFromRepo().values()]);
const pub = key.publicKey;View on GitHub (pinned to 433685b202)