Hmbown/CodeWhale · error · Error

unparsed Rust TRUSTED_KEYS entry

Error message

unparsed Rust TRUSTED_KEYS entry

What it means

After regex-extracting all TrustedKey entries from the table body, the checker verifies nothing remains except whitespace and commas. If leftover non-whitespace text exists, the table contained a construct the parser does not understand, and it throws rather than silently skipping keys — a security-relevant check since an unparsed key would be invisible to the comparison.

Solutions

  1. Look at what text remains unmatched — the error gives no offset, so diff the table against the regex: TrustedKey { key_id: "..", public_key: [..], status: KeyStatus::Active|Retired }.
  2. Update the parser regex if TrustedKey gained legitimate fields.
  3. Use only Active or Retired statuses in the table, or extend the alternation.
  4. Remove non-TrustedKey items or attributes from the array.

Example fix

// before (Rust)
#[allow(dead_code)]
TrustedKey { key_id: "old", ... },
// after
TrustedKey { key_id: "old", ... },
Defensive patterns

Strategy: validation

Validate before calling

const stripped = tableBody.replace(/TrustedKey\s*\{[^}]*\}/g, "").replace(/[\s,]/g, ""); if (stripped) throw new Error("unrecognized content in TRUSTED_KEYS: " + stripped.slice(0, 80));

Try / catch

try { parseRustKeys(src); } catch (e) { if (e.message.includes("unparsed")) console.error("TRUSTED_KEYS contains a construct the parser does not know"); throw e; }

Prevention

When it happens

Trigger: A TrustedKey entry formatted differently than the regex expects (extra fields, reordered fields, missing status, different brace style), a deprecated/retired key marked with an attribute like #[deprecated] or #[allow(...)] inside the table, or a non-TrustedKey item in the array.

Common situations: Adding a new field to TrustedKey (e.g. added_at) without updating the checker; using `KeyStatus::Revoked` (not Active|Retired) so the status alternation fails; multi-line formatting with attributes between entries.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/4182abc6b0c264a3. Report an issue: GitHub.

Appendix: source

Thrown at web/scripts/check-cloud-facts.mjs:26

const REPO_ROOT = resolve(WEB_ROOT, "..");
export { parseTsKeys };

export function parseRustKeys(text) {
  const source = text.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
  const tables = [...source.matchAll(/^\s*pub\s+const\s+TRUSTED_KEYS\s*:\s*&\s*\[TrustedKey\]\s*=\s*&\s*\[([\s\S]*?)\]\s*;/gm)];
  if (tables.length !== 1) throw new Error("cannot parse exactly one Rust TRUSTED_KEYS table");
  const table = tables[0];
  const body = table[1].replace(/^\s*\/\/.*$/gm, "");
  const keys = [];
  const remainder = body.replace(/TrustedKey\s*\{\s*key_id:\s*"([^"]+)",\s*public_key:\s*\[([^\]]*)\],\s*status:\s*KeyStatus::(Active|Retired)\s*,?\s*\}/g, (_, keyId, encoded, status) => {
    const pieces = encoded.split(",").map((piece) => piece.trim()).filter(Boolean);
    if (pieces.length !== 32 || pieces.some((piece) => !/^(?:\d+|0x[0-9a-fA-F]+)$/.test(piece))) throw new Error("Rust public key must contain 32 literal bytes");
    const bytes = pieces.map(Number);
    if (bytes.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) throw new Error("Rust public key byte out of range");
    keys.push({ keyId, publicKey: Buffer.from(bytes).toString("base64"), status: status.toLowerCase() });
    return "";
  });
  if (remainder.replace(/[\s,]/g, "")) throw new Error("unparsed Rust TRUSTED_KEYS entry");
  return validateTrustedKeys(keys);
}

function text(path) { return readBoundedFile(path).toString("utf8"); }
function json(path) { return JSON.parse(text(path)); }

export function checkCloudFacts() {
  const failures = [];
  const source = json(resolve(REPO_ROOT, "docs/cloud-facts/stable.json"));
  for (const error of validateSource(source)) failures.push(`stable.json: ${error}`);
  if (source.channel !== "stable") failures.push("stable.json: channel must be stable");
  const latest = json(resolve(WEB_ROOT, "data/latest-published-release.json"));
  if (source.release?.latest !== latest.version) failures.push("stable.json release.latest differs from latest-published-release.json");
  if (source.release?.release_url && source.release.release_url !== latest.url) failures.push("stable.json release.release_url differs from latest-published-release.json");
  // An explicit empty table is valid and inert; parse failures are never empty.
  const rustKeys = parseRustKeys(text(resolve(REPO_ROOT, "crates/config/src/cloud_facts/keys.rs")));
  const tsKeys = parseTsKeys(text(resolve(WEB_ROOT, "lib/cloud-facts/keys.ts")));
  if (JSON.stringify(rustKeys) !== JSON.stringify(tsKeys)) failures.push("Rust and web pinned key tables diverge");

View on GitHub (pinned to 433685b202)