remotion-dev/remotion · error · TypeError

"${name}" must be <= ${max}, but got ${JSON.stringify(value)

Error message

"${name}" must be <= ${max}, but got ${JSON.stringify(value)}

What it means

Thrown by the `roughenEdges()` effect when a numeric prop exceeds its documented upper bound. `validateAtMost` is applied to three resolved props: `border` (max 200), `scale` (max 4), and `seed` (max 1000). Values up to and including the max are allowed; anything strictly greater throws. The check runs after defaults are applied, so omitting a prop never trips this.

Source

Thrown at packages/effects/src/roughen-edges.ts:105

		readonly uAmount: WebGLUniformLocation | null;
		readonly uBorder: WebGLUniformLocation | null;
		readonly uScale: WebGLUniformLocation | null;
		readonly uSeed: WebGLUniformLocation | null;
		readonly uNoiseTexture: WebGLUniformLocation | null;
	};
	cachedNoiseSeed: number;
};

const resolve = (p: RoughenEdgesParams): RoughenEdgesResolved => ({
	amount: p.amount ?? DEFAULT_AMOUNT,
	border: p.border ?? DEFAULT_BORDER,
	scale: p.scale ?? DEFAULT_SCALE,
	seed: p.seed ?? DEFAULT_SEED,
});

const validateAtMost = (value: number, max: number, name: string): void => {
	if (value > max) {
		throw new TypeError(
			`"${name}" must be <= ${max}, but got ${JSON.stringify(value)}`,
		);
	}
};

const validateRoughenEdgesParams = (params: RoughenEdgesParams): void => {
	assertEffectParamsObject(params, 'Roughen edges');
	assertOptionalFiniteNumber(params.amount, 'amount');
	assertOptionalFiniteNumber(params.border, 'border');
	assertOptionalFiniteNumber(params.scale, 'scale');
	assertOptionalFiniteNumber(params.seed, 'seed');

	const r = resolve(params);
	validateUnitInterval(r.amount, 'amount');
	validateNonNegative(r.border, 'border');
	validateAtMost(r.border, MAX_BORDER, 'border');
	if (r.scale <= 0) {
		throw new TypeError(

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Bring the value within range: `border` ≤ 200, `scale` ≤ 4, `seed` ≤ 1000.
  2. Clamp animated values with `Math.min(max, value)` or `interpolate(..., {extrapolateRight: 'clamp'})`.
  3. Validate serialized presets before passing them to `roughenEdges()`.

Example fix

// before
roughenEdges({border: interpolate(frame, [0, 100], [0, 300])});
// after
roughenEdges({
  border: interpolate(frame, [0, 100], [0, 200], {extrapolateRight: 'clamp'}),
});
Defensive patterns

Strategy: validation

Validate before calling

const ROUGHEN_BOUNDS = {
  border: {min: 0, max: 200},
  scale: {min: 0.01, max: 4},
  seed: {min: 0, max: 1000},
} as const;

const clampRoughenProp = (
  value: number,
  bound: {min: number; max: number},
): number => Math.min(bound.max, Math.max(bound.min, value));

// before calling roughenEdges()
const safe = {
  border: clampRoughenProp(config.border ?? 26.5, ROUGHEN_BOUNDS.border),
  scale: clampRoughenProp(config.scale ?? 0.07, ROUGHEN_BOUNDS.scale),
  seed: clampRoughenProp(config.seed ?? 231.2, ROUGHEN_BOUNDS.seed),
};
roughenEdges(safe);

Type guard

const isWithinRoughenBounds = (
  value: unknown,
  min: number,
  max: number,
): value is number =>
  typeof value === 'number' &&
  Number.isFinite(value) &&
  value >= min &&
  value <= max;

Prevention

When it happens

Trigger: Call `roughenEdges({border: 250})`, `roughenEdges({scale: 5})`, or `roughenEdges({seed: 1500})`. Also triggered by animating past the cap without clamping, e.g. `interpolate(frame, [0, 100], [0, 300])` for `border`.

Common situations: Loading serialized presets that were authored against a different max; copying values from another tool's slider scale; animating a prop with an unclamped output range.

Related errors


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