heygen-com/hyperframes · error · Error

LUT for "${cell.label}" is not a valid .cube: ${normalizeErr

Error message

LUT for "${cell.label}" is not a valid .cube: ${normalizeErrorMessage(err)}

What it means

Thrown by prepareGradeCompareTempProject when a LUT file exists and was read, but failed validation by `parseCubeLut(lutText, { maxSize: 64 })`. The .cube parser enforces the standard format and a 64-entry size cap; a corrupt, truncated, oversized, or non-.cube file is rejected before staging so the render doesn't fail later in the browser with an opaque shader error.

Source

Thrown at packages/cli/src/commands/grade-compare.ts:449

  const tempDir = mkdtempSync(join(tmpdir(), "hf-grade-compare-"));
  try {
    const frameFileName = opts.frameFileName ?? frameFileNameForPath(opts.framePath);
    writeFileSync(join(tempDir, frameFileName), opts.frameBuffer);

    let lutIndex = 0;
    const stagedCells = opts.cells.map((cell) => {
      const lutSrc = lutSrcFromGrading(cell.grading);
      if (!lutSrc) return cell;

      const sourcePath = resolveFromBase(opts.projectDir, lutSrc);
      if (!existsSync(sourcePath)) {
        throw new Error(`LUT file not found for "${cell.label}": ${sourcePath}`);
      }
      const lutText = readFileSync(sourcePath, "utf-8");
      try {
        parseCubeLut(lutText, { maxSize: 64 });
      } catch (err) {
        throw new Error(
          `LUT for "${cell.label}" is not a valid .cube: ${normalizeErrorMessage(err)}`,
        );
      }
      const lutExt = extname(sourcePath) || ".cube";
      const stagedName = `lut-${lutIndex}${lutExt}`;
      lutIndex += 1;
      copyFileSync(sourcePath, join(tempDir, stagedName));
      return {
        label: cell.label,
        grading: rewriteGradingLutSrc(cell.grading, stagedName),
      };
    });

    const html = buildGradeCompareHtml({
      cells: stagedCells,
      frameSrc: frameFileName,
      frameWidth: opts.frameWidth,
      frameHeight: opts.frameHeight,

View on GitHub (pinned to c2996c8626)

Solutions

  1. Open the named .cube file and verify it is a valid 3D .cube LUT with a LUT_3D_SIZE line ≤ 64.
  2. Re-export or re-download the LUT from its source in binary mode.
  3. If the LUT is genuinely larger than 64 points, downsample it with a LUT tool — HyperFrames will not raise the cap.
  4. Check the inner error message (appended after the colon) for the specific parse failure.
Defensive patterns

Strategy: validation

Validate before calling

// Validate a .cube file out-of-band before grading
import { parseCubeLut } from "@hyperframes/core";
import { readFileSync } from "node:fs";
function assertValidCube(path: string): void {
  const text = readFileSync(path, "utf-8");
  parseCubeLut(text, { maxSize: 64 }); // throws on invalid
}

Try / catch

try {
  await prepareGradeCompareTempProject(opts);
} catch (err) {
  if (/not a valid .cube/.test((err as Error).message))) {
    // re-derive or replace the offending LUT; message names the cell + inner cause
  }
  throw err;
}

Prevention

When it happens

Trigger: A .cube file that is malformed (bad header, wrong line counts, non-numeric rows), exceeds 64 grid points, is actually a different format with a .cube extension, or was truncated by a bad download/git checkout.

Common situations: Downloading a 1D LUT and renaming to .cube; a text-mode FTP/git operation that mangled line endings or truncated the file; a LUT exported at 65+ points (the cap is 64); copy-paste introducing stray characters.

Related errors


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