ruvnet/ruflo · error · Error
canonical JSON does not support ${typeof item}
Error message
canonical JSON does not support ${typeof item} What it means
This branch catches any remaining non-object value that is not null/boolean/string/number/undefined — in practice symbol, bigint, and function — and embeds its typeof in the message (e.g. 'canonical JSON does not support bigint'). JSON has no representation for these types, and silently stringifying them would produce non-canonical output, so they are rejected with the type named.
Source
Thrown at v3/@claude-flow/codex/src/harness/repository-state.ts:129
const encode = (item: unknown): string => {
if (item === null || typeof item === 'boolean') return JSON.stringify(item);
if (typeof item === 'string') {
assertUnicodeScalarString(item);
return JSON.stringify(item);
}
if (typeof item === 'number') {
if (
!Number.isFinite(item)
|| Object.is(item, -0)
|| (Number.isInteger(item) && !Number.isSafeInteger(item))
) {
throw new Error('canonical JSON requires finite, safe, non-negative-zero numbers');
}
return JSON.stringify(item);
}
if (item === undefined) throw new Error('canonical JSON does not support undefined');
if (typeof item !== 'object') {
throw new Error(`canonical JSON does not support ${typeof item}`);
}
if (ancestors.has(item)) throw new Error('canonical JSON does not support cycles');
ancestors.add(item);
try {
if (Array.isArray(item)) return `[${item.map(encode).join(',')}]`;
const prototype = Object.getPrototypeOf(item);
if (prototype !== Object.prototype && prototype !== null) {
throw new Error('canonical JSON supports only arrays and plain objects');
}
const entries = Object.entries(item as Record<string, unknown>)
.sort(([left], [right]) => codeUnitCompare(left, right));
return `{${entries.map(([key, child]) => {
assertUnicodeScalarString(key);
return `${JSON.stringify(key)}:${encode(child)}`;
}).join(',')}}`;
} finally {
ancestors.delete(item);
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Convert bigint leaves to strings while building the payload (String(n) or n.toString())
- Pass evidence through a JSON.stringify replacer pre-pass that stringifies bigint and drops symbols/functions
- Type payloads as a JsonValue structure so the compiler rejects these types at the boundary
Example fix
// before
canonicalJson({ fileId: BigInt('9007199254740993') });
// after
canonicalJson({ fileId: '9007199254740993' }); Defensive patterns
Strategy: type-guard
Validate before calling
function toCanonicalValue(value: unknown): unknown {
if (typeof value === 'bigint') return value.toString();
if (typeof value === 'symbol' || typeof value === 'function') return undefined; // drop
if (Array.isArray(value)) return value.map(toCanonicalValue);
if (typeof value === 'object' && value !== null) {
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, toCanonicalValue(v)]));
}
return value;
} Type guard
type CanonicalJsonValue = null | boolean | number | string | CanonicalJsonValue[] | { [key: string]: CanonicalJsonValue };
function isCanonicalJsonValue(value: unknown): value is CanonicalJsonValue {
if (value === null || ['boolean', 'number', 'string'].includes(typeof value)) return true;
if (Array.isArray(value)) return value.every(isCanonicalJsonValue);
if (typeof value === 'object') {
return Object.getPrototypeOf(value) === Object.prototype
&& Object.values(value).every(isCanonicalJsonValue);
}
return false;
} Try / catch
try {
return canonicalJson(payload);
} catch (error) {
if (error instanceof Error && error.message.startsWith('canonical JSON does not support ')
&& /bigint|symbol|function/.test(error.message)) {
return canonicalJson(toCanonicalValue(payload));
}
throw error;
} Prevention
- Convert bigint to string at the driver boundary (postgres int64, BSON Long, crypto values)
- Type evidence payloads as CanonicalJsonValue so symbols/functions fail to compile
- Pass payloads through JSON.stringify with a replacer as a cheap pre-flight check
When it happens
Trigger: Evidence containing BigInt hashes or 64-bit integer IDs from crypto/database clients (postgres int64, BSON Long); Symbol values or symbol-keyed data leaking through spreads; class methods enumerated into the payload.
Common situations: node:crypto or driver APIs returning BigInt; schemas parsed with bigint support; passing rich objects whose enumerable properties include bound functions.
Related errors
- canonical JSON does not support lone UTF-16 surrogates
- canonical JSON requires finite, safe, non-negative-zero numb
- canonical JSON does not support undefined
- canonical JSON does not support cycles
- canonical JSON supports only arrays and plain objects
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/7f18e7ddc82bc1cf.
Report an issue: GitHub.