remotion-dev/remotion · error · TypeError

The units of the start and end values must match. Start…

Error message

The units of the start and end values must match. Start value: ${initialStyleProperty}, end value: ${finalStyleProperty}

What it means

Thrown by interpolateStyles when both the start and end parts are numeric but their units differ and neither value is zero. interpolateStyles allows a 0 on either side to pair with any unit (0 is unit-agnostic), but any other numeric pair must share the same unit so the numbers can be linearly blended.

Solutions

  1. Convert one side so both keyframes use the same unit (e.g. '50%' to '750px' at a known container width).
  2. If you must cross units, set one side to the literal 0 (number) — 0 pairs with any unit.
  3. Pre-compute unit conversions before building the outputStyles array.

Example fix

// before
interpolateStyles(frame, [0, 30], [
  {width: '100px'},
  {width: '50%'},  // unit mismatch
]);

// after
interpolateStyles(frame, [0, 30], [
  {width: '100px'},
  {width: '750px'},  // same unit
]);
Defensive patterns

Strategy: validation

Validate before calling

const unitOf = (v: string): string => {
  const m = v.match(/^(-?\d+(?:\.\d+)?)([a-z%]*)/i);
  return m ? m[2] : '';
};
const unitsCompatible = (a: unknown, b: unknown): boolean => {
  if (typeof a === 'number' || typeof b === 'number') return true; // 0 is unit-agnostic
  if (typeof a === 'string' && typeof b === 'string') {
    return unitOf(a) === unitOf(b);
  }
  return false;
};

Prevention

When it happens

Trigger: Keyframes like {width: '100px'} to {width: '50%'}; or {transform: 'translate(10px,0)'} to {transform: 'translate(0,1em)'} where the non-zero sides use different units.

Common situations: Mixing px and % across keyframes; switching between rem and px; copy-pasting values from design tools that use different units.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/59eb8157889ffa2c. Report an issue: GitHub.

Appendix: source

Thrown at packages/animation-utils/src/transformation-helpers/interpolate-styles/index.tsx:111

		}(${interpolatedFunctionArgs.slice(2)})`;
	}

	if (typeof initialStylePropertyPart.number === 'undefined') {
		if (initialStylePropertyPart.unit !== finalStylePropertyPart.unit) {
			throw new TypeError(
				`Non-animatable values cannot be interpolated. Start value: ${initialStyleProperty}, end value: ${finalStyleProperty}`,
			);
		}

		return `${initialStylePropertyPart.unit}`;
	}

	if (
		initialStylePropertyPart.unit !== finalStylePropertyPart.unit &&
		initialStylePropertyPart.number !== 0 &&
		finalStylePropertyPart.number !== 0
	) {
		throw new TypeError(
			`The units of the start and end values must match. Start value: ${initialStyleProperty}, end value: ${finalStyleProperty}`,
		);
	}

	const startNumber = initialStylePropertyPart.number;
	const endNumber = finalStylePropertyPart.number || 0;
	const interpolatedNumber = interpolate(
		inputValue,
		inputRange,
		[startNumber, endNumber],
		options,
	);
	const interpolatedUnit =
		initialStylePropertyPart.unit || finalStylePropertyPart.unit || '';

	if (!interpolatedUnit) {
		return interpolatedNumber;
	}

View on GitHub (pinned to 78fe4bb3fd)