Hmbown/CodeWhale · error · Error
non-finite number in payload
Error message
non-finite number in payload
What it means
canonicalize in facts-publish.mjs produces canonical JSON for signing. JSON cannot represent NaN, Infinity, or -Infinity, so if it encounters a non-finite number while serializing it throws this error rather than emitting 'null' (JSON.stringify's silent default) which would break signature reproducibility.
Solutions
- Sanitize the payload before canonicalizing: replace or remove non-finite numbers
- Use Number.isFinite() on every numeric field before building the payload
- Store such values as strings or null explicitly if they must appear
Example fix
// before
const facts = { uptime: 1 / 0 };
canonicalize(facts);
// after
const facts = { uptime: Number.isFinite(raw) ? raw : null };
canonicalize(facts); Defensive patterns
Strategy: validation
Validate before calling
function assertFiniteNumbers(obj) {
for (const [k, v] of Object.entries(obj)) {
if (typeof v === 'number' && !Number.isFinite(v)) throw new Error(`${k} is not finite`);
if (v && typeof v === 'object') assertFiniteNumbers(v);
}
}
assertFiniteNumbers(payload); Type guard
const isFiniteNumber = (v) => typeof v === 'number' && Number.isFinite(v);
Try / catch
try { canonicalize(payload); } catch (e) { if (e.message === 'non-finite number in payload') { payload = sanitize(payload); canonicalize(payload); } else throw e; } Prevention
- Run Number.isFinite on computed metrics before adding them to facts
- Never rely on JSON.stringify to mask NaN/Infinity
- Represent unknown numerics as null or strings
When it happens
Trigger: Calling canonicalize(value) where value — or any nested member — is NaN, Infinity, or -Infinity, e.g. buildPayload/serialize path given facts computed with a division by zero.
Common situations: Building facts from metrics computed with parseFloat('x'), 0/0, or Math.log(-1); JSON.stringify silently writes null but this canonicalizer refuses.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- <dynamic: wrapped serde_json serialization error>
- <dynamic: wrapped serde_json serialization error>
- {error}
- Failed to parse MCP config
- Failed to render MCP template JSON
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/c2ccaf2fed26aa48.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/facts-publish.mjs:51
export const SCHEMA_VERSION = 1;
export const MAX_PAYLOAD_BYTES = 512 * 1024;
export const MAX_ENVELOPE_BYTES = 768 * 1024;
const KEY_ID_RE = /^cwf-[a-z0-9-]{1,32}$/;
const CHANNEL_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
const CI_MARKERS = ["CI", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "CIRCLECI", "JENKINS_URL", "TF_BUILD"];
const here = dirname(fileURLToPath(import.meta.url));
const WEB_ROOT = resolve(here, "..");
const REPO_ROOT = resolve(WEB_ROOT, "..");
// ---------------------------------------------------------------------------
// Canonical JSON + signing primitives (exported for tests)
// ---------------------------------------------------------------------------
export function canonicalize(value) {
if (value === null || typeof value !== "object") {
if (typeof value === "number" && !Number.isFinite(value)) {
throw new Error("non-finite number in payload");
}
return JSON.stringify(value);
}
if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
const keys = Object.keys(value).sort();
const parts = [];
for (const key of keys) {
const v = value[key];
if (v === undefined) continue;
parts.push(`${JSON.stringify(key)}:${canonicalize(v)}`);
}
return `{${parts.join(",")}}`;
}
export function signingMessage(keyId, payloadBytes) {
return Buffer.concat([Buffer.from(DOMAIN, "utf8"), Buffer.from(keyId, "utf8"), Buffer.from([0]), payloadBytes]);
}
View on GitHub (pinned to 433685b202)