Popmotion/popmotion · error
Array of easing functions must be of length `input.length -
Error message
Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.
What it means
When the `ease` option is an array of easing functions, `interpolate` requires exactly `input.length - 1` easers, because easings apply to the transitions *between* consecutive input stops, not to the stops themselves. `invariant` throws when the array is longer or shorter. A single easing function (non-array) is fine and is applied to all segments.
Source
Thrown at packages/popmotion/src/utils/interpolate.ts:130
*
* mixColor(0.5) // 'rgba(128, 128, 128, 1)'
* ```
*
* @public
*/
export function interpolate<T>(
input: number[],
output: T[],
{ clamp: isClamp = true, ease, mixer }: InterpolateOptions<T> = {}
) {
const inputLength = input.length;
invariant(
inputLength === output.length,
'Both input and output ranges must be the same length'
);
invariant(
!ease || !Array.isArray(ease) || ease.length === inputLength - 1,
'Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.'
);
// If input runs highest -> lowest, reverse both arrays
if (input[0] > input[inputLength - 1]) {
input = [].concat(input);
output = [].concat(output);
input.reverse();
output.reverse();
}
const mixers = createMixers(output, ease, mixer);
const interpolator =
inputLength === 2
? fastInterpolate(input, mixers)
: slowInterpolate(input, mixers);View on GitHub (pinned to adf681efd8)
Solutions
- Make `ease.length === input.length - 1` (one easing per segment between stops)
- If you want the same easing everywhere, pass a single function instead of an array: `ease: easeInOut`
- Count segments as `input.length - 1`, not `input.length`
- Validate the ease array length against the input range before calling
Example fix
// before
interpolate([0, 0.5, 1], [0, 100, 200], { ease: [linear, linear, linear] });
// after
interpolate([0, 0.5, 1], [0, 100, 200], { ease: [linear, linear] }); Defensive patterns
Strategy: validation
Validate before calling
function validateEase(input, ease) {
if (Array.isArray(ease) && ease.length !== input.length - 1) {
throw new Error(`ease array must have ${input.length - 1} items (segments), got ${ease.length}`);
}
}
// call before interpolate(input, output, { ease }) Type guard
function isValidEaseArray<T>(input: number[], ease: unknown): ease is ((t: number) => T)[] {
return Array.isArray(ease) && ease.length === input.length - 1 && ease.every(fn => typeof fn === 'function');
} Prevention
- Count segments as input.length - 1, never input.length
- Prefer passing a single easing function when all segments share easing
- Add a unit test asserting ease array length for programmatically built easings
- When changing the number of keyframes, update the ease array in the same commit
When it happens
Trigger: `interpolate([0, 0.5, 1], ['0px','100px','200px'], { ease: [linear, linear, linear] })` (3 easers for 2 segments), or `{ ease: [linear] }` for a 3-stop input, or building the ease array dynamically and miscounting segments.
Common situations: Off-by-one confusion: developers assume one easing per input value instead of one per segment; copying an ease array from a config with a different number of keyframes; programmatic ease generation.
Related errors
- Both input and output ranges must be the same length
- '${color}' is not an animatable color. Use the equivalent co
- Complex values '${origin}' and '${target}' too different to
AI-assisted analysis of Popmotion/popmotion@adf681efd8 (2026-09-02).
Data as JSON: /api/errors/3cb0a9c5b9a87644.
Report an issue: GitHub.