remotion-dev/remotion · error · TypeError

"colors" must be an array with at least 2 colors, but got ${

Error message

"colors" must be an array with at least 2 colors, but got ${JSON.stringify(colors)}

What it means

Zigzag requires a colors array with at least two entries (it samples a 1-D palette texture indexed by stripe position, so a single color is meaningless). validateColors throws a TypeError if colors is omitted-but-not-undefined, not an array, or has fewer than two elements; each entry must then pass assertRequiredColor (a non-empty string). Note undefined is allowed because colors defaults to ['#dff4ff','#7cc6ff'].

Source

Thrown at packages/effects/src/zigzag.ts:216

		);
	}
};

const validateNonNegative = (value: number, name: string): void => {
	if (value < 0) {
		throw new TypeError(
			`"${name}" must be greater than or equal to 0, but got ${JSON.stringify(value)}`,
		);
	}
};

const validateColors = (colors: unknown): void => {
	if (colors === undefined) {
		return;
	}

	if (!Array.isArray(colors) || colors.length < 2) {
		throw new TypeError(
			`"colors" must be an array with at least 2 colors, but got ${JSON.stringify(colors)}`,
		);
	}

	for (let i = 0; i < colors.length; i++) {
		assertRequiredColor(colors[i], `colors[${i}]`);
	}
};

const validateDirection = (direction: unknown): void => {
	if (direction === undefined) {
		return;
	}

	if (
		typeof direction !== 'string' ||
		!ZIGZAG_DIRECTIONS.includes(direction as ZigzagDirection)
	) {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Always provide at least two color strings: zigzag({colors: ['#ff0000', '#00ff00']}).
  2. If building the list dynamically, guard length before passing: colors.length >= 2 ? colors : undefined (lets the default apply).
  3. Ensure each entry is a parseable CSS color string, not an object or empty string.

Example fix

// before
zigzag({colors: []});            // throws
zigzag({colors: ['#ff0000']});    // throws
zigzag({colors: '#ff0000'});      // throws

// after
zigzag({colors: ['#ff0000', '#00ff00']});
zigzag({colors: list.length >= 2 ? list : undefined});
Defensive patterns

Strategy: type-guard

Validate before calling

import {zigzag} from '@remotion/effects';

const colors = userInputColors; // unknown shape

if (!Array.isArray(colors) || colors.length < 2 ||
    !colors.every((c) => typeof c === 'string' && c.length > 0)) {
  // fall back to default palette by omitting colors
  zigzag({});
} else {
  zigzag({colors: colors as [string, string, ...string[]]});
}

Type guard

const isZigzagColors = (v: unknown): v is [string, string, ...string[]] =>
  Array.isArray(v) &&
  v.length >= 2 &&
  v.every((c) => typeof c === 'string' && c.length > 0);

// usage:
zigzag({colors: isZigzagColors(colors) ? colors : undefined});

Try / catch

try {
  return <VideoEffects effects={[zigzag({colors})]} />;
} catch (err) {
  if (err instanceof TypeError && /colors.*array with at least 2/.test(err.message)) {
    return <VideoEffects effects={[zigzag({colors: ['#dff4ff', '#7cc6ff']})]} />;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling zigzag({colors: []}), zigzag({colors: ['#ff0000']}), zigzag({colors: null}), zigzag({colors: 'red'}), or zigzag({colors: 42}).

Common situations: Passing a single-color array expecting a solid fill; passing a CSS color string instead of an array; spreading a possibly-empty list; setting colors from data that may contain one item.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/c16940889e22229c. Report an issue: GitHub.