remotion-dev/remotion · error · TypeError
"${name}" must be a [number, number] tuple
Error message
"${name}" must be a [number, number] tuple What it means
Thrown by the `rings()` effect when `center` is supplied but is not a `[number, number]` tuple of finite numbers. `center` is the ring origin in normalized UV coordinates (each component later constrained to [0,1] by `validateUnitInterval`). The validator requires a two-element array where every element is a finite number; anything else (wrong length, strings, `NaN`, objects) is rejected.
Source
Thrown at packages/effects/src/rings.ts:182
);
}
for (let i = 0; i < colors.length; i++) {
assertRequiredColor(colors[i], `colors[${i}]`);
}
};
const assertOptionalCenter = (value: unknown, name: string): void => {
if (value === undefined) {
return;
}
if (
!Array.isArray(value) ||
value.length !== 2 ||
value.some((item) => typeof item !== 'number' || !Number.isFinite(item))
) {
throw new TypeError(`"${name}" must be a [number, number] tuple`);
}
validateUnitInterval(value[0], `${name}[0]`);
validateUnitInterval(value[1], `${name}[1]`);
};
const validateRingsParams = (params: RingsParams): void => {
assertEffectParamsObject(params, 'Rings');
validateColors(params.colors);
assertOptionalCenter(params.center, 'center');
assertOptionalFiniteNumber(params.thickness, 'thickness');
assertOptionalFiniteNumber(params.gap, 'gap');
assertOptionalFiniteNumber(params.offset, 'offset');
assertOptionalBoolean(params.maskToSourceAlpha, 'maskToSourceAlpha');
const thickness = params.thickness ?? DEFAULT_THICKNESS;
const gap = params.gap ?? DEFAULT_GAP;
validatePositive(thickness, 'thickness');View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Pass a two-element numeric tuple such as `center: [0.5, 0.5]`.
- Omit `center` to use the default `[0.5, 0.5]`.
- Convert point objects with `center: [point.x, point.y]` and ensure both are finite before passing.
Example fix
// before
rings({center: pointerPosition}); // {x: number, y: number}
// after
rings({center: [pointerPosition.x, pointerPosition.y]}); Defensive patterns
Strategy: validation
Validate before calling
const validateRingsCenter = (center: unknown): [number, number] | undefined => {
if (center === undefined) return undefined;
if (!Array.isArray(center) || center.length !== 2 ||
center.some((c) => typeof c !== 'number' || !Number.isFinite(c))) {
throw new TypeError('center must be a [number, number] tuple');
}
const [x, y] = center as [number, number];
if (x < 0 || x > 1 || y < 0 || y > 1) {
throw new TypeError('center components must be within [0, 1]');
}
return [x, y];
};
rings({center: validateRingsCenter(maybeCenter)}); Type guard
const isRingsCenter = (v: unknown): v is [number, number] => Array.isArray(v) && v.length === 2 && v.every((c) => typeof c === 'number' && Number.isFinite(c));
Prevention
- Always pass `center` as a tuple literal `[x, y]`, not a point object.
- When reading from JSON, coerce strings with `Number()` and validate finiteness.
- Constrain interactive drag handlers so the returned value is always a 2-tuple.
When it happens
Trigger: Call `rings({center: [0.5]})`, `rings({center: [0.5, 0.5, 0]})`, `rings({center: {x: 0.5, y: 0.5}})`, `rings({center: ['0.5', '0.5']})`, or `rings({center: [0.5, Number.NaN]})`. Each component is also range-checked, so `center: [1.5, 0.5]` will instead throw the `validateUnitInterval` `">= 0"` / `"<= 1"` error on `center[0]`.
Common situations: Passing an `{x, y}` point object from a drag handler instead of a tuple; reading center from JSON where numbers became strings; reusing a 3D `[x,y,z]` vector; off-by-one when slicing a longer array.
Related errors
- "${name}" must be greater than or equal to 0, but got ${JSON
- "colors" must be an array with at least 2 colors, but got ${
- "${name}" must be greater than 0, but got ${JSON.stringify(v
- "${name}" must be greater than or equal to 0, but got ${JSON
- "colors" must be an array with at least 2 colors, but got ${
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/696a701b5db83566.
Report an issue: GitHub.