remotion-dev/remotion · error · TypeError
"origin" must be a [number, number] tuple
Error message
"origin" must be a [number, number] tuple
What it means
The starburst effect's optional `origin` parameter must be a `[number, number]` tuple. This TypeError is thrown by `validateStarburstEffectParams` when `origin` is present but is not a 2-element array, or when either element is not a finite number (NaN, Infinity, string, etc.). It runs during the effect's `validateParams` phase before any GPU work begins, so it surfaces as a configuration error at render time.
Source
Thrown at packages/effects/src/starburst.ts:142
throw new TypeError(
`"smoothness" must be a finite number, but got ${JSON.stringify(params.smoothness)}`,
);
}
if (r.smoothness < 0 || r.smoothness > 1) {
throw new RangeError(
`"smoothness" must be between 0 and 1, but got ${r.smoothness}`,
);
}
if (
!Array.isArray(r.origin) ||
r.origin.length !== 2 ||
r.origin.some((coordinate) => {
return typeof coordinate !== 'number' || !Number.isFinite(coordinate);
})
) {
throw new TypeError('"origin" must be a [number, number] tuple');
}
if (r.origin.some((coordinate) => coordinate < 0 || coordinate > 1)) {
throw new RangeError(
`"origin" must contain coordinates between 0 and 1, but got ${JSON.stringify(r.origin)}`,
);
}
for (const c of r.colors) {
colorToRgb(c);
}
};
const STARBURST_VS = /* glsl */ `#version 300 es
in vec2 aPos;
in vec2 aUv;
out vec2 vUv;
void main() {View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Set `origin` to a tuple of two finite numbers between 0 and 1, e.g. `origin: [0.5, 0.5]`.
- Omit `origin` entirely to use the default `[0.5, 0.5]`.
- If computing origin dynamically, guard each component with `Number.isFinite()` before passing it in.
Example fix
// before
starburst({rays: 6, colors: ['#f00', '#00f'], origin: [0.5, NaN]});
// after
starburst({rays: 6, colors: ['#f00', '#00f'], origin: [0.5, 0.5]}); Defensive patterns
Strategy: validation
Validate before calling
const isOriginTuple = (v: unknown): v is readonly [number, number] =>
Array.isArray(v) &&
v.length === 2 &&
v.every((c) => typeof c === 'number' && Number.isFinite(c));
const params = {rays: 6, colors: ['#f00', '#00f'], origin: computeOrigin()};
if (params.origin !== undefined && !isOriginTuple(params.origin)) {
throw new Error('Invalid starburst origin');
} Type guard
const isStarburstOrigin = (v: unknown): v is readonly [number, number] => Array.isArray(v) && v.length === 2 && v.every((c) => typeof c === 'number' && Number.isFinite(c));
Try / catch
try {
starburst({...params});
} catch (e) {
if (e instanceof TypeError && /origin.*tuple/.test(e.message)) {
// fall back to default origin
starburst({...params, origin: [0.5, 0.5]});
} else throw e;
} Prevention
- Always type `origin` as `readonly [number, number]` and let TypeScript enforce the tuple shape.
- Validate dynamically-computed origins with `Number.isFinite` on both components before passing.
- Omit `origin` when you want the default center rather than passing an explicit value.
When it happens
Trigger: Passing `origin` as a non-array (e.g. `origin: 'center'`), an array with wrong length (e.g. `origin: [0.5]` or `origin: [0.5, 0.5, 0.5]`), or an array containing non-numbers/non-finite values (e.g. `origin: [0.5, NaN]`, `origin: ['0.5', '0.5']`, `origin: [Infinity, 0.5]`).
Common situations: Typo or copy-paste from another API that accepts string origins; deserializing origin from JSON where numbers became strings; computing origin dynamically and accidentally producing NaN via a division by zero or undefined input; TypeScript types bypassed via `as any`.
Related errors
- "origin" must contain coordinates between 0 and 1, but got $
- "${name}" must be a [number, number] tuple
- "${name}" must be a [number, number] tuple
- "${name}" must be a [number, number] tuple
- ${name} params must be an object
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/8c807c1d0f37fc94.
Report an issue: GitHub.