heygen-com/hyperframes · error · Error
[chunkEncoder] lockGopForChunkConcat=true requires a positiv
Error message
[chunkEncoder] lockGopForChunkConcat=true requires a positive integer gopSize (received ${String(options.gopSize)}) What it means
Thrown by the H.264/H.265 software encoder branch in chunkEncoder when lockGopForChunkConcat is true but gopSize is not a positive finite number. Closed-GOP encoding forces fixed keyframe intervals (-g, -keyint_min, -sc_threshold 0, -force_key_frames) so chunk files can be concatenated with ffmpeg -c copy without frozen seams. Without a valid GOP size, these flags cannot be set and concat-copy playback would break.
Source
Thrown at packages/engine/src/services/chunkEncoder.ts:254
const encoderName = codec === "h264" ? "libx264" : "libx265";
args.push("-c:v", encoderName, "-preset", preset);
if (bitrate) args.push("-b:v", bitrate);
else args.push("-crf", String(quality));
// Closed-GOP / forced-keyframe args so an external orchestrator can
// ffmpeg-concat chunk files with `-c copy`. Without these, libx264 /
// libx265 emit open-GOP frames with mid-chunk scenecut keyframes; the
// first frame of each chunk isn't an independently-decodable IDR and
// concat-copy playback freezes at chunk seams on some decoders.
const lockGop = options.lockGopForChunkConcat === true;
let gop = 0;
if (lockGop) {
if (
typeof options.gopSize !== "number" ||
!Number.isFinite(options.gopSize) ||
options.gopSize <= 0
) {
throw new Error(
`[chunkEncoder] lockGopForChunkConcat=true requires a positive integer gopSize (received ${String(options.gopSize)})`,
);
}
gop = Math.floor(options.gopSize);
args.push(
"-g",
String(gop),
"-keyint_min",
String(gop),
"-sc_threshold",
"0",
"-force_key_frames",
`expr:eq(mod(n,${gop}),0)`,
);
}
// Disable B-frames. Standard h264 with B-frames produces negative DTS
// at the start of the stream (the first B-frame's decode order isView on GitHub (pinned to c2996c8626)
Solutions
- Set gopSize to the frame rate (for 1-second GOPs) or 2x frame rate: e.g., gopSize: 60 for 60fps.
- If you don't need concat-copy compatibility, set lockGopForChunkConcat: false instead.
- Validate config at load time: if lockGopForChunkConcat is true, assert gopSize is a positive integer before encoding.
- Check that your config parser coerces gopSize to a number (parseInt or Number()) rather than passing a string.
Example fix
// before
encodeChunk(input, output, {
codec: 'h264',
lockGopForChunkConcat: true,
// gopSize missing!
});
// after
encodeChunk(input, output, {
codec: 'h264',
lockGopForChunkConcat: true,
gopSize: frameRate * 2, // closed GOP at 2-second intervals
}); Defensive patterns
Strategy: validation
Validate before calling
function validateEncoderOptions(options: EncodeChunkOptions): void {
if (options.lockGopForChunkConcat === true) {
if (typeof options.gopSize !== 'number' || !Number.isFinite(options.gopSize) || options.gopSize <= 0) {
throw new Error('lockGopForChunkConcat requires gopSize to be a positive integer');
}
}
}
validateEncoderOptions(options); Type guard
function hasValidGopSize(options: unknown): options is { gopSize: number; lockGopForChunkConcat: true } {
if (typeof options !== 'object' || options === null) return false;
const o = options as Record<string, unknown>;
return o.lockGopForChunkConcat === true
&& typeof o.gopSize === 'number'
&& Number.isFinite(o.gopSize)
&& o.gopSize > 0;
} Prevention
- Always pair lockGopForChunkConcat: true with a positive integer gopSize in config templates.
- Validate config at load time rather than at encode time to fail fast.
- Use a shared config schema (e.g., zod) to enforce the dependency between lockGopForChunkConcat and gopSize.
When it happens
Trigger: encodeChunk() (or equivalent) is called with options.lockGopForChunkConcat === true and options.gopSize that is undefined, NaN, Infinity, zero, negative, or a non-number. The validation checks typeof !== 'number', !Number.isFinite(), and <= 0.
Common situations: lockGopForChunkConcat was set to true by default in an orchestrator config but gopSize was never configured. A config merge overwrote gopSize with undefined. A CLI flag parser produced a string instead of a number. gopSize was set to 0 thinking it means 'auto'.
Related errors
- This FFmpeg build has neither libx264 nor VideoToolbox H.264
- [renderToLambda] bucketName is required
- [renderToLambda] stateMachineArn is required
- [renderToLambda] either siteHandle or projectDir must be sup
- [validateConfig] config: Step Functions execution input is n
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/76cf76f1d1a4ba76.
Report an issue: GitHub.