{"record":{"id":"f65d348db822b9b5","repo":"remotion-dev/remotion","slug":"name-must-be-a-number-number-tuple-f65d34","errorCode":null,"errorMessage":"\"${name}\" must be a [number, number] tuple","messagePattern":"\"(.+?)\" must be a \\[number, number\\] tuple","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/linear-gradient.ts","lineNumber":112,"sourceCode":"\nconst resolve = (p: LinearGradientParams): LinearGradientResolved => ({\n\tstart: [...(p.start ?? DEFAULT_START)] as LinearGradientUvCoordinate,\n\tend: [...(p.end ?? DEFAULT_END)] as LinearGradientUvCoordinate,\n\tstartColor: p.startColor ?? DEFAULT_START_COLOR,\n\tendColor: p.endColor ?? DEFAULT_END_COLOR,\n});\n\nconst assertOptionalUvCoordinate = (value: unknown, name: string): void => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\n\tif (\n\t\t!Array.isArray(value) ||\n\t\tvalue.length !== 2 ||\n\t\tvalue.some((item) => typeof item !== 'number' || !Number.isFinite(item))\n\t) {\n\t\tthrow new TypeError(`\"${name}\" must be a [number, number] tuple`);\n\t}\n};\n\nconst validateLinearGradientParams = (params: LinearGradientParams): void => {\n\tassertEffectParamsObject(params, 'Linear gradient');\n\tassertOptionalUvCoordinate(params.start, 'start');\n\tassertOptionalUvCoordinate(params.end, 'end');\n\tassertOptionalColor(params.startColor, 'startColor');\n\tassertOptionalColor(params.endColor, 'endColor');\n};\n\nconst VERTEX_SHADER = /* glsl */ `#version 300 es\nin vec2 aPos;\nin vec2 aUv;\nout vec2 vUv;\n\nvoid main() {\n\tvUv = aUv;","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/linear-gradient.ts#L94-L130","documentation":"Thrown by linearGradient when `start` or `end` is provided but is not an array of exactly two finite numbers. These are UV coordinates in [0,1] space defining the gradient endpoints; `undefined` is allowed (optional), but any other non-tuple value is rejected.","triggerScenarios":"Passing `start: [0]`, `start: [0,0,0]`, `start: {x,y}`, `start: ['0','1']`, `start: [0, NaN]`, or `start: [0, Infinity]`. The guard requires a 2-element array where both entries are finite numbers.","commonSituations":"Passing pixel coordinates instead of UV; passing a Vec2-like object instead of a tuple; numbers deserialized to strings from JSON; off-by-one in array slicing producing wrong length.","solutions":["Pass UV tuples in [0,1]: `start: [0, 0]`, `end: [1, 1]`.","Convert pixel coords: `start: [px / width, py / height]`.","Validate both entries are finite numbers before calling.","Omit `start`/`end` to use the documented defaults."],"exampleFix":"// before\nlinearGradient({ start: [0, 0], end: [frameWidth, frameHeight] });\n\n// after\nlinearGradient({ start: [0, 0], end: [1, 1] });","handlingStrategy":"type-guard","validationCode":"const isUvTuple = (v: unknown): v is [number, number] =>\n  Array.isArray(v) &&\n  v.length === 2 &&\n  v.every((x) => typeof x === 'number' && Number.isFinite(x));\n\nconst start = isUvTuple(userStart) ? userStart : undefined;\nlinearGradient(start === undefined ? {} : { start });","typeGuard":"const isUvTuple = (v: unknown): v is [number, number] =>\n  Array.isArray(v) &&\n  v.length === 2 &&\n  v.every((x) => typeof x === 'number' && Number.isFinite(x));","tryCatchPattern":null,"preventionTips":["Always pass UV ([0,1]) coordinates, never pixel coordinates.","Validate the tuple shape before calling; omit the prop to use defaults.","When deserializing from JSON, coerce both elements to Number and check finiteness."],"tags":["validation","linear-gradient","effects","api-misuse"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}