remotion-dev/remotion · error · TypeError
"${name}" must be a hex color such as "#000000"
Error message
"${name}" must be a hex color such as "#000000" What it means
`parseHexColor` runs on `resolved.colorA`, `resolved.colorB`, and `resolved.backgroundColor` after `resolve()`. It requires a `#RRGGBB` hex string (with or without the leading `#`, case-insensitive, exactly 6 hex digits). The regex `/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i` rejects 3-digit shorthand, `rgba()`, named colors, and `#RRGGBBAA`.
Source
Thrown at packages/brand/src/effects/metallic-swirl-effect.ts:313
const assertOptionalEnum = <T extends string>(
value: unknown,
name: keyof MetallicSwirlParams,
variants: readonly T[],
): void => {
if (value === undefined) {
return;
}
if (typeof value !== 'string' || !variants.includes(value as T)) {
throw new TypeError(`"${name}" must be one of ${variants.join(', ')}`);
}
};
const parseHexColor = (hex: string, name: keyof MetallicSwirlParams): Rgb => {
const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (!match) {
throw new TypeError(`"${name}" must be a hex color such as "#000000"`);
}
return [
parseInt(match[1], 16) / 255,
parseInt(match[2], 16) / 255,
parseInt(match[3], 16) / 255,
];
};
const validateMetallicSwirlParams = (
params: MetallicSwirlParams = {},
): void => {
assertParamsObject(params, 'Metallic swirl');
assertOptionalFiniteNumber(params.time, 'time');
assertOptionalFiniteNumber(params.speed, 'speed');
assertOptionalFiniteNumber(params.zoom, 'zoom');
assertOptionalFiniteNumber(params.iterations, 'iterations');
assertOptionalFiniteNumber(params.sampleGap, 'sampleGap');View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Expand to 6-digit hex: `'#fff'` → `'#ffffff'`.
- Convert named colors and rgb()/hsl() strings to `#RRGGBB` before passing.
- Strip any alpha channel into the separate `opacity` field.
- Validate with the same regex at your input boundary.
Example fix
// before
metallicSwirl({colorA: '#fff', backgroundColor: 'black'});
// after
metallicSwirl({colorA: '#ffffff', backgroundColor: '#000000'}); Defensive patterns
Strategy: validation
Validate before calling
// Validate / normalize color strings to #RRGGBB before passing.
const HEX6 = /^#?([a-f\d]{6})$/i;
const toHex6 = (v: unknown): string => {
if (typeof v !== 'string') {
throw new Error('color must be a string');
}
const trimmed = v.trim();
if (HEX6.test(trimmed)) {
return trimmed.startsWith('#') ? trimmed : `#${trimmed}`;
}
// expand 3-digit shorthand
const short = /^#?([a-f\d]{3})$/i.exec(trimmed);
if (short) {
const [, d] = short;
return `#${d.split('').map((c) => c + c).join('')}`;
}
throw new Error(`color must be #RRGGBB hex, got ${JSON.stringify(v)}`);
};
metallicSwirl({colorA: toHex6(raw.colorA)}); Type guard
const isHex6Color = (v: unknown): v is string =>
typeof v === 'string' && /^#?[a-f\d]{6}$/i.test(v.trim()); Prevention
- Use 6-digit hex (`#RRGGBB`) for all color params; expand 3-digit shorthand.
- Convert named colors, rgb()/hsl() strings to hex at your boundary.
- Move alpha into the separate `opacity` field, not an 8-digit hex.
- Configure color pickers to output hex format.
When it happens
Trigger: `metallicSwirl({colorA: 'red'})`, `metallicSwirl({colorA: '#fff'})` (3-digit), `metallicSwirl({backgroundColor: 'rgb(0,0,0)'})`, `metallicSwirl({colorA: '#ff0038ff'})` (8-digit), `metallicSwirl({colorA: '00000x'})`.
Common situations: Using 3-digit shorthand from design tokens; passing CSS named colors; alpha-channel hex (`#RRGGBBAA`); color picker outputs that default to rgb()/hsl() strings.
Related errors
- "backgroundColor" must be a string
- "colorA" must be a string
- "colorB" must be a string
- ${name} params must be an object
- "${name}" must be a finite number
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/9a9a8c2882bb006d.
Report an issue: GitHub.