heygen-com/hyperframes · error · Error
Engine config snapshot must be a plain object
Error message
Engine config snapshot must be a plain object
What it means
validateEngineConfigSnapshot() is the entry guard and first asserts the top-level value is a plain object (prototype is Object.prototype or null). Arrays, class instances, null, primitives, or objects with a non-trivial prototype are rejected before any field validation runs. This protects the deep field-walking validators from receiving malformed input.
Source
Thrown at packages/engine/src/config.ts:516
"pageSideCompositingAutoDisabled",
"forceScreenshotExplicitlyOptedOut",
"streamingEncodeAutoDisabledOnWin32Compound",
] as const) {
if (config[field] !== undefined && typeof config[field] !== "boolean") {
throw new Error(`Engine config ${field} must be a boolean`);
}
}
}
/**
* Validate a complete EngineConfig crossing a JSON wire boundary.
*
* `resolveConfig()` intentionally accepts partial programmatic overrides, but
* a serialized render request stores a resolved snapshot. Accepting a partial
* snapshot would skip the orchestrator's `resolveConfig()` fallback entirely.
*/
export function validateEngineConfigSnapshot(value: unknown): asserts value is EngineConfig {
if (!isPlainObject(value)) throw new Error("Engine config snapshot must be a plain object");
validateRequiredEngineConfigFields(value);
validateEngineConfigScalars(value);
validateEngineConfigParallelism(value);
validateEngineConfigVp9(value);
validateEngineConfigRuntime(value);
validateEngineConfigHdr(value);
validateOptionalEngineConfigFields(value);
}
/**
* Reference canvas area for the baseline `protocolTimeout`: 1080p. A single CDP
* call (`Runtime.callFunctionOn` seek+paint, or `Page.captureScreenshot`)
* scales with the *output pixel area* it has to render/serialize — NOT with the
* frame count (that governs total wall-clock, capped separately by the ffmpeg
* streaming inactivity timeout). A fixed 300s ceiling intermittently kills
* legitimate slow-but-valid renders on large canvases with
* `Runtime.callFunctionOn timed out`, so we scale the per-call ceiling with
* area.View on GitHub (pinned to c2996c8626)
Solutions
- Ensure the value passed is a single plain object literal `{...}` (or JSON.parse of an object document).
- If the payload is wrapped (e.g. `{ config: {...} }`), unwrap to the inner object first.
- JSON.parse the inbound string and confirm `typeof === "object" && !Array.isArray && value !== null` before calling.
Example fix
// before const payload = JSON.parse(body); // e.g. an array or envelope validateEngineConfigSnapshot(payload); // after const payload = JSON.parse(body); const cfg = Array.isArray(payload) ? payload[0] : payload.config ?? payload; validateEngineConfigSnapshot(cfg);
Defensive patterns
Strategy: type-guard
Validate before calling
function isPlainObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value)
&& [Object.prototype, null].includes(Object.getPrototypeOf(value));
}
if (!isPlainObject(snapshot)) throw new Error("engine config snapshot must be a plain object"); Type guard
function isPlainObject(value: unknown): value is Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null;
} Try / catch
try {
validateEngineConfigSnapshot(payload);
} catch (e) {
if (/snapshot must be a plain object/.test(String(e))) {
throw new TypeError(`Malformed render request: expected a config object, got ${Array.isArray(payload) ? "array" : typeof payload}`, { cause: e });
}
throw e;
} Prevention
- JSON.parse the inbound body and confirm it is a single object before validating.
- Unwrap envelopes ({config: {...}}) before calling validateEngineConfigSnapshot.
- Do not pass class instances; pass plain object literals.
When it happens
Trigger: Passing a JSON-deserialized array, a class instance (e.g. a Map or a custom Config class with extra prototype), null, undefined, a string, or a plain JSON value that is not an object to validateEngineConfigSnapshot().
Common situations: Deserializing a render request whose body root is an array or a wrapped envelope; double-wrapping the config in another object; passing a Promise/thenable that resolved to a non-object; a malformed IPC payload.
Related errors
- Engine config ${field} must be a ${integer ? "finite integer
- Engine config snapshot is missing required field ${field}
- Row ${index} must be a JSON object of variable values.
- Placeholder {${key}} in row ${index} must resolve to a strin
- Grades file must be a JSON array of { label, grading } objec
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/91a06a5ab222aa13.
Report an issue: GitHub.