Hmbown/CodeWhale · error · Error
--key-id must match cwf-[a-z0-9-]
Error message
--key-id must match cwf-[a-z0-9-]{1,32} What it means
The keygen subcommand validates the --key-id flag against KEY_ID_RE (cwf-[a-z0-9-]{1,32}) and throws this if it does not match. Key IDs are used as database identifiers in the pinned trust table, so the format is enforced up front.
Solutions
- Pass an id matching cwf- followed by 1-32 lowercase letters, digits, or hyphens, e.g. --key-id cwf-prod-2026-01
- Lowercase and hyphenate the intended name before generating the key
- Re-run with quotes removed and no whitespace in the flag value
Example fix
// before node facts-publish.mjs keygen --key-id "Codewhale_Prod" // after node facts-publish.mjs keygen --key-id cwf-codewhale-prod
Defensive patterns
Strategy: validation
Validate before calling
const KEY_ID_RE = /^cwf-[a-z0-9-]{1,32}$/;
if (!KEY_ID_RE.test(keyId)) throw new Error(`key id must match cwf-[a-z0-9-]{1,32}, got: ${keyId}`); Try / catch
try {
await run(['keygen', '--key-id', keyId, '--out', outPath]);
} catch (e) {
if (e.message.includes('--key-id must match')) console.error('Use lowercase letters, digits, hyphens only, 1-32 chars after cwf-');
throw e;
} Prevention
- Normalize names to lowercase kebab-case before keygen
- Never include dots, underscores, or whitespace in key ids
- Keep key ids <= 32 chars after the cwf- prefix
When it happens
Trigger: Running `facts-publish.mjs keygen --key-id <bad>` where the id is missing, uppercase, too long (>32 chars after the prefix), missing the cwf- prefix, or contains characters outside [a-z0-9-] (dots, underscores, spaces).
Common situations: Typing a human-readable id like "Codewhale_Prod_2026" or "stable.v2"; omitting --key-id entirely so it becomes an empty string; copying a key id with surrounding whitespace or quotes.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- A positive pull request number is required
- API key contains invalid control characters
- API key id must be lowercase hex characters — the part…
- API key input is unexpectedly large
- API key must be - UTF-8 bytes
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/8d27f7823c49fae5.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/facts-publish.mjs:511
function readJson(path) {
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(readBoundedFile(path)));
}
function nowIso() {
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
}
async function main(argv) {
const { positional, flags } = parseArgs(argv);
const cmd = positional[0];
if (!cmd || flags.help) {
console.log(readFileSync(fileURLToPath(import.meta.url), "utf8").split("\n").slice(1, 26).join("\n"));
return 0;
}
if (cmd === "keygen") {
const keyId = String(flags["key-id"] ?? "");
if (!KEY_ID_RE.test(keyId)) throw new Error("--key-id must match cwf-[a-z0-9-]{1,32}");
const out = flags.out ? resolve(String(flags.out)) : null;
if (!out) throw new Error("--out <path> is required (write the private key OUTSIDE any repository)");
refuseUnderCi();
const { privateKey, publicKey } = generateKeyPairSync("ed25519");
mkdirSync(dirname(out), { recursive: true, mode: 0o700 });
const fd = openSync(out, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 0o600);
try { writeFileSync(fd, privateKey.export({ type: "pkcs8", format: "pem" })); }
finally { closeSync(fd); }
const raw = rawPublicKeyFromKeyObject(publicKey);
console.log(JSON.stringify({
key_id: keyId,
algorithm: "ed25519",
public_key_b64: raw.toString("base64"),
public_key_bytes: [...raw],
private_key_file: out,
note: "Private key written with mode 0600. Move it into custody (password manager); never commit it.",
}, null, 2));
return 0;View on GitHub (pinned to 433685b202)