remotion-dev/remotion · error · TypeError
"${name}" must be a [number, number] tuple
Error message
"${name}" must be a [number, number] tuple What it means
pattern() validates its optional 'origin' prop (a UV coordinate) and requires it, when supplied, to be an array of exactly two finite numbers. This TypeError fires before any GPU work when the value is present but malformed (wrong length, non-array, or non-finite entries like NaN/Infinity).
Source
Thrown at packages/effects/src/pattern.ts:231
rowOffset: p.rowOffset ?? DEFAULT_OFFSET,
rowOffsetEvery: p.rowOffsetEvery ?? DEFAULT_OFFSET_EVERY,
columnOffset: p.columnOffset ?? DEFAULT_OFFSET,
columnOffsetEvery: p.columnOffsetEvery ?? DEFAULT_OFFSET_EVERY,
origin: [...(p.origin ?? DEFAULT_ORIGIN)] as PatternOrigin,
wrap: p.wrap ?? DEFAULT_WRAP,
});
const assertOptionalUvCoordinate = (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`);
}
};
const assertOptionalInteger = (value: unknown, name: string): void => {
if (value === undefined) {
return;
}
if (!Number.isInteger(value)) {
throw new TypeError(
`"${name}" must be an integer, but got ${JSON.stringify(value)}`,
);
}
};
const validatePositive = (value: number, name: string): void => {
if (value <= 0) {
throw new TypeError(`"${name}" must be > 0`);View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Pass origin as a readonly [number, number] tuple of finite values, e.g. [0.5, 0.5].
- Omit origin entirely to accept the default [0, 0].
- Coerce inputs from your data layer into the tuple shape before calling pattern().
- If animating, guard the computed components with Number.isFinite before forwarding.
Example fix
// before
pattern({ origin: 'center' })
pattern({ origin: [0.5] })
// after
pattern({ origin: [0.5, 0.5] })
// or omit it:
pattern({ scale: 0.2 }) Defensive patterns
Strategy: type-guard
Validate before calling
// Validate origin before calling pattern().
function isValidOrigin(v: unknown): v is readonly [number, number] {
return Array.isArray(v) && v.length === 2 && v.every((n) => typeof n === 'number' && Number.isFinite(n));
}
if (originInput !== undefined && !isValidOrigin(originInput)) {
throw new Error('origin must be a [number, number] tuple of finite values');
}
pattern({ origin: originInput }); Type guard
const isUvTuple = (v: unknown): v is readonly [number, number] => Array.isArray(v) && v.length === 2 && v.every((item) => typeof item === 'number' && Number.isFinite(item));
Prevention
- Type origin as PatternOrigin (readonly [number, number]) in your own prop types.
- Sanitize data from JSON/config into tuples before forwarding to pattern().
- When animating origin components, guard each with Number.isFinite.
- Omit origin to accept the [0, 0] default rather than passing null/undefined inside the tuple.
When it happens
Trigger: Calling pattern({ origin: <value> }) where <value> is defined but not a 2-tuple of finite numbers, e.g. origin: [0.5], origin: 'center', origin: [0, NaN], origin: {x:0,y:0}. The check assertOptionalUvCoordinate runs in validatePatternParams during effect setup.
Common situations: Passing origin as a string or object from a config/UI; reading origin from JSON that truncated the array; animated values producing NaN via division by zero; passing a 3-element vector by mistake.
Related errors
- "${name}" must be a [number, number] tuple
- "${name}" must be a [number, number] tuple
- "${name}" must be an integer, but got ${JSON.stringify(value
- "${name}" must be > 0
- "${name}" must be >= ${min}, but got ${JSON.stringify(value)
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/b17ad265d86a7f03.
Report an issue: GitHub.