ruvnet/ruflo · error · Error
undefined array member at ${path}[${i}]
Error message
undefined array member at ${path}[${i}] What it means
Thrown by assertJsonValue() inside canonicalizeJcs() during RFC-8785 JCS-style canonicalization. JSON has no 'undefined' type, so an array element that is literally the JavaScript value `undefined` cannot be serialized canonically and would make the receipt hash non-reproducible. The ${path}[${i}] placeholder points at the exact offending location in the value tree (e.g. $.heldOutDeltas[2]).
Source
Thrown at v3/@claude-flow/cli/src/services/flywheel-receipt.ts:157
termVerification?: TermVerification[];
now?: number;
ttlMs?: number;
privateKeyPem?: string;
publicKeyPem?: string;
bootstrapIterations?: number;
}
function assertJsonValue(value: unknown, path = '$'): void {
if (value === null || typeof value === 'string' || typeof value === 'boolean') return;
if (typeof value === 'number') {
if (!Number.isFinite(value) || Object.is(value, -0)) {
throw new Error(`non-canonical number at ${path}`);
}
return;
}
if (Array.isArray(value)) {
value.forEach((v, i) => {
if (v === undefined) throw new Error(`undefined array member at ${path}[${i}]`);
assertJsonValue(v, `${path}[${i}]`);
});
return;
}
if (typeof value === 'object') {
for (const [key, child] of Object.entries(value as Record<string, unknown>)) {
if (child === undefined) throw new Error(`undefined property at ${path}.${key}`);
assertJsonValue(child, `${path}.${key}`);
}
return;
}
throw new Error(`unsupported JSON value at ${path}`);
}
/**
* RFC-8785-compatible for the JSON domain accepted above: ECMAScript primitive
* serialization plus recursively sorted UTF-16 property names.
*/View on GitHub (pinned to 6b01dc5a68)
Solutions
- Sanitize arrays before receipt creation: arr.filter((x) => x !== undefined).
- Replace undefined slots with null (a valid JSON type) only if the consuming code treats null semantically.
- Delete the property/omit the element at the source so the array never carries undefined.
- If the value comes from external/JSON input, parse with a reviver that drops undefined.
Example fix
// before
const policy = { weights: [1, undefined, 3] };
createFlywheelReceipt({ candidatePolicy: policy, /* ... */ });
// after
const policy = { weights: [1, undefined, 3].filter((x) => x !== undefined) };
createFlywheelReceipt({ candidatePolicy: policy, /* ... */ }); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeForCanonical<T>(value: T): T {
if (Array.isArray(value)) return value.filter((v) => v !== undefined).map(sanitizeForCanonical) as T;
if (value && typeof value === 'object') {
return Object.fromEntries(
Object.entries(value as Record<string, unknown>)
.filter(([, v]) => v !== undefined)
.map(([k, v]) => [k, sanitizeForCanonical(v)])
) as T;
}
return value;
}
// run before createFlywheelReceipt / canonicalizeJcs:
const safe = sanitizeForCanonical(candidatePolicy); Type guard
function hasNoUndefined(value: unknown): boolean {
if (value === undefined) return false;
if (Array.isArray(value)) return value.every(hasNoUndefined);
if (value && typeof value === 'object')
return Object.values(value).every(hasNoUndefined);
return true;
} Try / catch
try {
const ref = policyCandidateId(policy);
} catch (e) {
if (e instanceof Error && /undefined array member/.test(e.message)) {
throw new Error(`candidatePolicy is not JSON-canonical: ${e.message}`);
}
throw e;
} Prevention
- Build policy objects with conditional assignment, never { ...opts } where opts may have undefined values.
- Run a recursive undefined-strip on any externally-sourced object before receipt hashing.
- Add a unit test that asserts canonicalizeJcs succeeds on every policy your code produces.
When it happens
Trigger: Calling createFlywheelReceipt(), canonicalizeJcs(), policyCandidateId(), or sha256Ref() with a candidatePolicy / heldOutDeltas / any nested object that contains an array slot holding `undefined` (e.g. arr[2] = undefined, or [1, , 3] sparse-array coercion, or a map/filter that left an undefined element).
Common situations: A candidatePolicy record built from partial config where an array field was conditionally assigned undefined instead of being omitted; heldOutDeltas produced by a pipeline that can yield NaN/undefined slots; objects deserialized then re-extended with undefined defaults.
Related errors
- undefined property at ${path}.${key}
- unsupported JSON value at ${path}
- ${label} requires a JSON argument
- ${label} must be valid JSON
- ${toolsJson} must contain a JSON array of {name, description
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/cedc5e3d456e9887.
Report an issue: GitHub.