heygen-com/hyperframes · error · AudioFxChainError
Chain file must be a JSON object.
Error message
Chain file must be a JSON object.
What it means
After JSON.parse succeeds, parseAudioFxChain() requires the top-level value to be a JSON object (typeof === 'object' && non-null). A JSON array, number, string, boolean, or null at the top level is rejected because the chain schema is { version, nodes }. This guards against a syntactically valid but structurally wrong chain file.
Source
Thrown at packages/core/src/audioFx.ts:768
super(message);
this.name = "AudioFxChainError";
}
}
/**
* Parse a chain file. Unknown effect ids are rejected rather than skipped: a
* chain that silently loses a node would render differently from the project
* the author saved, which is worse than refusing to render at all.
*/
export function parseAudioFxChain(json: string): HfAudioFxChain {
let raw: unknown;
try {
raw = JSON.parse(json);
} catch (err) {
throw new AudioFxChainError(`Chain file is not valid JSON: ${(err as Error).message}`);
}
if (typeof raw !== "object" || raw === null) {
throw new AudioFxChainError("Chain file must be a JSON object.");
}
const obj = raw as { version?: unknown; nodes?: unknown };
if (obj.version !== HF_AUDIO_FX_CHAIN_VERSION) {
throw new AudioFxChainError(`Unsupported chain version: ${String(obj.version)}`);
}
if (!Array.isArray(obj.nodes)) {
throw new AudioFxChainError("Chain file is missing a `nodes` array.");
}
const nodes: HfAudioFxNode[] = obj.nodes.map((n, i) => {
if (typeof n !== "object" || n === null) {
throw new AudioFxChainError(`Node ${i} is not an object.`);
}
const node = n as { type?: unknown; enabled?: unknown; params?: unknown };
if (typeof node.type !== "string" || !BY_ID.has(node.type)) {
throw new AudioFxChainError(`Node ${i} has unknown effect type: ${String(node.type)}`);
}
return {
type: node.type,View on GitHub (pinned to c2996c8626)
Solutions
- Wrap the content in an object literal: { "version": 1, "nodes": [ ... ] }.
- Regenerate with serializeAudioFxChain to guarantee the correct top-level shape.
Example fix
// before
parseAudioFxChain(JSON.stringify([{ type: "highpass" }])); // array at top level
// after
parseAudioFxChain(JSON.stringify({ version: 1, nodes: [{ type: "highpass" }] })); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeChainObject(s: string): boolean {
try { const v = JSON.parse(s); return typeof v === "object" && v !== null && !Array.isArray(v); }
catch { return false; }
} Type guard
function isChainObject(raw: unknown): raw is Record<string, unknown> {
return typeof raw === "object" && raw !== null && !Array.isArray(raw);
} Try / catch
try { parseAudioFxChain(json); }
catch (err) { if (/must be a JSON object/.test(String(err))) { /* wrap nodes in {version,nodes} */ } else throw err; } Prevention
- Always wrap nodes in { version: HF_AUDIO_FX_CHAIN_VERSION, nodes: [...] }.
- Use serializeAudioFxChain to produce the correct top-level shape.
When it happens
Trigger: The chain string parses as a bare scalar or array — e.g. `[]`, `[{...nodes...}]` (wrapping nodes in an array instead of an object), `"hello"`, `42`, `null`, or `true`.
Common situations: Author writes the nodes array directly without the enclosing { version, nodes } object; a tool serializes just the nodes array; confusion between the chain object and its nodes field.
Related errors
- Chain file is not valid JSON: ${(err as Error).message}
- Chain file is missing a `nodes` array.
- Node ${i} is not an object.
- Unsupported chain version: ${String(obj.version)}
- Node ${i} has unknown effect type: ${String(node.type)}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/cdbaa344c048b0b0.
Report an issue: GitHub.