Hmbown/CodeWhale · error · Error
Rust public key must contain 32 literal bytes
Error message
Rust public key must contain 32 literal bytes
What it means
Within a parsed TrustedKey entry, the `public_key` field must contain exactly 32 numeric literal bytes (decimal or 0x hex), matching an Ed25519 public key size. The parser throws when the encoded array does not yield exactly 32 valid byte literals, e.g. when the Rust literal was truncated, comma formatting confused the splitter, or comments/expressions remain inside the array.
Solutions
- Count the bytes in the offending public_key array; it must be exactly 32 numeric literals.
- Remove type suffixes (e.g. `12u8` → `12`) and expressions; use plain decimal or 0x hex.
- Regenerate the key literal from the canonical base64 key rather than hand-editing.
- Check for comments inside the array that survive stripping and split wrongly.
Example fix
// before (Rust) public_key: [0x8au8, 0x1fu8, /* 30 more */], // after public_key: [0x8a, 0x1f, /* exactly 32 plain literals */],
Defensive patterns
Strategy: validation
Validate before calling
const m = entry.match(/public_key:\s*\[([^\]]*)\]/); const parts = m[1].split(",").map(s => s.trim()).filter(Boolean); if (parts.length !== 32 || parts.some(p => !/^(?:\d+|0x[0-9a-fA-F]+)$/.test(p))) throw new Error("bad key literal"); Try / catch
try { parseRustKeys(src); } catch (e) { if (e.message.includes("32 literal bytes")) inspectKeyArrays(src); throw e; } Prevention
- Generate Rust key literals with a script from base64, never by hand.
- Avoid u8 suffixes and expressions inside public_key arrays.
- Keep comments out of the array body.
- Re-run the checker after every key edit.
When it happens
Trigger: A TrustedKey whose public_key array has fewer/more than 32 elements, contains expressions like `0u8` suffixes or computed values, or elements that are neither decimal nor 0x-hex literals after comment stripping.
Common situations: Key was hand-edited and a byte dropped; key stored in a format the parser does not accept (e.g. string literal or `[u8; 32]` const reference); a `u8` suffix on bytes breaks the number regex.
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
- Rust public key byte out of range
- unparsed Rust TRUSTED_KEYS entry
- A pinned task provider requires an explicit model
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/53a2831028dbebb2.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/check-cloud-facts.mjs:20
/** Local source, release, pinned-key parity and public-fixture gate. */
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { validateSource, verifyEnvelope, parseTsKeys, validateTrustedKeys, readBoundedFile } from "./facts-publish.mjs";
const WEB_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
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"));View on GitHub (pinned to 433685b202)