remotion-dev/remotion · error

Expected LUT colors, got .

Error message

Expected ${data.length / 3} LUT colors, got ${offset / 3}.

What it means

The number of color rows in a .cube file must exactly match the declared size: size rows for 1D LUTs, size^3 for 3D LUTs. After parsing, if the number of collected colors (offset/3) differs from data.length/3, this error is thrown reporting both counts. Unlike the 'got more' variant this fires when the table is incomplete — too few color lines.

Solutions

  1. Re-export or re-download the LUT file — truncation is the usual cause.
  2. Adjust the size header down to match the actual row count if the table itself is intact (count data lines: 1D -> n, 3D -> cube root of n).
  3. Compare the reported 'Expected X LUT colors, got Y' counts to determine whether the header or the data is wrong.
  4. Validate the file length beforehand: count non-header lines and check against size^3.

Example fix

// before: 32768 rows but header says 33^3=35937
LUT_3D_SIZE 33
// after (table has 32^3=32768 rows)
LUT_3D_SIZE 32
Defensive patterns

Strategy: validation

Validate before calling

const size = Number(/LUT_3D_SIZE\s+(\d+)/.exec(text)?.[1] ?? NaN);
const rows = text.split(/\r?\n/).filter((l) => {
  const p = l.trim().split(/\s+/);
  return p.length === 3 && p.every((x) => Number.isFinite(Number(x)));
}).length;
if (Number.isFinite(size) && rows !== size ** 3) {
  throw new Error(`Expected ${size ** 3} colors, file has ${rows}`);
}

Try / catch

try {
  const lut = parseCubeLut(text);
} catch (e) {
  const m = /Expected (\d+) LUT colors, got (\d+)/.exec((e as Error).message);
  if (m) console.error(`Table truncated: have ${m[2]} of ${m[1]} colors`);
}

Prevention

When it happens

Trigger: parseCubeLut(text) where declared LUT_3D_SIZE is 33 but only e.g. 30000 color lines follow (truncated download), or a 1D LUT declaring 32 entries but containing fewer; also a wrong size value (declaring 33 for a 32-entry table).

Common situations: Interrupted downloads/uploads truncating the tail of the file; text editors or copy-paste dropping the last lines; size header incremented without regenerating the table.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18). Data as JSON: /api/errors/bdcfded6c093c8c6. Report an issue: GitHub.

Appendix: source

Thrown at packages/studio/src/helpers/cube-lut.ts:130

			!color.every((value) => Number.isFinite(Math.fround(value)))
		) {
			throw new Error(`Invalid LUT color on line ${index + 1}.`);
		}

		if (offset + 3 > data.length) {
			throw new Error(`Expected ${data.length / 3} LUT colors, got more.`);
		}

		data.set(color, offset);
		offset += 3;
	}

	if (type === null || data === null) {
		throw new Error('Expected LUT_1D_SIZE or LUT_3D_SIZE.');
	}

	if (offset !== data.length) {
		throw new Error(
			`Expected ${data.length / 3} LUT colors, got ${offset / 3}.`,
		);
	}

	if (domainMin.some((min, channel) => min >= domainMax[channel])) {
		throw new Error(
			'DOMAIN_MAX must be greater than DOMAIN_MIN in every channel.',
		);
	}

	if (
		domainMin.some((min, channel) => !Number.isFinite(domainMax[channel] - min))
	) {
		throw new Error('LUT input ranges must be finite.');
	}

	if (
		(headers.has('LUT_1D_INPUT_RANGE') || headers.has('LUT_3D_INPUT_RANGE')) &&

View on GitHub (pinned to 46a3a6bf13)