{"record":{"id":"638047f2df419d81","repo":"remotion-dev/remotion","slug":"colors-must-be-an-array-with-at-least-2-colors-638047","errorCode":null,"errorMessage":"\"colors\" must be an array with at least 2 colors, but got ${JSON.stringify(colors)}","messagePattern":"\"colors\" must be an array with at least 2 colors, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/rings.ts","lineNumber":162,"sourceCode":"\t\t);\n\t}\n};\n\nconst validateNonNegative = (value: number, name: string): void => {\n\tif (value < 0) {\n\t\tthrow new TypeError(\n\t\t\t`\"${name}\" must be greater than or equal to 0, but got ${JSON.stringify(value)}`,\n\t\t);\n\t}\n};\n\nconst validateColors = (colors: unknown): void => {\n\tif (colors === undefined) {\n\t\treturn;\n\t}\n\n\tif (!Array.isArray(colors) || colors.length < 2) {\n\t\tthrow new TypeError(\n\t\t\t`\"colors\" must be an array with at least 2 colors, but got ${JSON.stringify(colors)}`,\n\t\t);\n\t}\n\n\tfor (let i = 0; i < colors.length; i++) {\n\t\tassertRequiredColor(colors[i], `colors[${i}]`);\n\t}\n};\n\nconst assertOptionalCenter = (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))","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/rings.ts#L144-L180","documentation":"Thrown by the `rings()` effect when `colors` is supplied but is not an array, or is an array with fewer than 2 entries. The effect cycles colors across concentric rings, so a single color would make every ring identical and is treated as a configuration error. `undefined` is allowed (defaults to `['#dff4ff', '#7cc6ff']`); only a present-but-invalid value throws.","triggerScenarios":"Call `rings({colors: ['#dff4ff']})` (one entry), `rings({colors: []})`, `rings({colors: 'red'})`, or `rings({colors: ['#fff', '']})` (the empty string is later rejected by `assertRequiredColor`). Also hit when a dynamically-built palette array is filtered down to fewer than 2 items at runtime.","commonSituations":"Building the palette from data that may collapse to one element (e.g. `colors: data.map(d => d.color)` where `data` is short); spreading a user-supplied array without a length check; passing a CSS color string instead of an array of strings.","solutions":["Provide at least two color strings, e.g. `colors: ['#dff4ff', '#7cc6ff']`.","Omit `colors` entirely to accept the default two-color palette.","When building the array dynamically, guard with `if (palette.length >= 2) rings({colors: palette}); else rings({});`."],"exampleFix":"// before\nrings({colors: data.map((d) => d.color)});\n// after\nconst palette = data.map((d) => d.color);\nrings({colors: palette.length >= 2 ? palette : undefined});","handlingStrategy":"validation","validationCode":"const validateRingsColors = (colors: unknown): string[] | undefined => {\n  if (colors === undefined) return undefined;\n  if (!Array.isArray(colors) || colors.length < 2 ||\n      colors.some((c) => typeof c !== 'string' || c.length === 0)) {\n    throw new TypeError('colors must be an array of >= 2 non-empty strings');\n  }\n  return colors as string[];\n};\n\nrings({colors: validateRingsColors(maybeColors)});","typeGuard":"const isRingsColors = (v: unknown): v is string[] =>\n  Array.isArray(v) &&\n  v.length >= 2 &&\n  v.every((c) => typeof c === 'string' && c.length > 0);","tryCatchPattern":null,"preventionTips":["Build palette arrays from data with a length check before passing them in.","Provide a fallback palette constant when dynamic data may collapse below 2 entries.","Omit `colors` to accept the default rather than risking an invalid array."],"tags":["validation","rings-effect","effects","params","colors"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}