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 is

View on GitHub (pinned to c2996c8626)

Solutions

  1. Set gopSize to the frame rate (for 1-second GOPs) or 2x frame rate: e.g., gopSize: 60 for 60fps.
  2. If you don't need concat-copy compatibility, set lockGopForChunkConcat: false instead.
  3. Validate config at load time: if lockGopForChunkConcat is true, assert gopSize is a positive integer before encoding.
  4. 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

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


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/76cf76f1d1a4ba76. Report an issue: GitHub.