Hmbown/CodeWhale · error · Error

${result.failures.join("\n - ")}

Error message

${result.failures.join("\n  - ")}

What it means

The check-cloud-facts CLI entry point throws when checkCloudFacts() returns a non-empty failures array, joining all cross-check failures (facts version, key sets, active key counts between the web facts and the Rust/TS sources) into one multi-line message. The message is dynamic: it lists every concrete mismatch found.

Solutions

  1. Read each `- ` bullet in the thrown message; it names the exact mismatch.
  2. Regenerate or hand-update the facts JSON so keys, versions, and counts match the Rust/TS sources.
  3. If a key was rotated, update BOTH the Rust TRUSTED_KEYS table and the web facts in the same commit.
  4. Re-run the script until it prints `check-cloud-facts: OK`.
Defensive patterns

Strategy: validation

Validate before calling

// before running, diff facts against sources yourself:
// node web/scripts/check-cloud-facts.mjs && echo ready

Try / catch

try { const r = checkCloudFacts(); if (r.failures.length) console.error("mismatches:\n  - " + r.failures.join("\n  - ")); } catch (e) { console.error(e.message); }

Prevention

When it happens

Trigger: Running the script when the deployed/web facts JSON disagrees with source code: a trusted key was rotated in Rust but not in the facts JSON, facts_version was bumped inconsistently, or active-key counts differ.

Common situations: A key rotation PR updated one side only; facts JSON regenerated from a stale branch; CI catching drift between web and native key material before deploy.

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/b80156224ab1b6f7. Report an issue: GitHub.

Appendix: source

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

  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");
  const testOnlyPub = text(resolve(REPO_ROOT, "docs/cloud-facts/fixtures/test-only.pub")).trim();
  for (const name of ["envelope-stable-v7.json", "envelope-future-only-v8.json"]) {
    const result = verifyEnvelope(json(resolve(REPO_ROOT, "docs/cloud-facts/fixtures", name)), testOnlyPub);
    if (!result.ok) failures.push(`fixture ${name}: ${result.errors.join("; ")}`);
  }
  if ([...rustKeys, ...tsKeys].some((key) => key.publicKey === testOnlyPub || key.keyId === "cwf-test-only")) failures.push("TEST-ONLY keys must never be production trust anchors");
  return { failures, factsVersion: source.facts_version, activeKeys: tsKeys.filter((key) => key.status === "active").length };
}

if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
  try {
    const result = checkCloudFacts();
    if (result.failures.length) throw new Error(result.failures.join("\n  - "));
    console.log(`check-cloud-facts: OK (facts_version=${result.factsVersion}, ${result.activeKeys} active production keys)`);
  } catch (error) {
    console.error(`check-cloud-facts: FAIL\n  - ${error.message}`);
    process.exitCode = 1;
  }
}

View on GitHub (pinned to 433685b202)