remotion-dev/remotion · error · TypeError
"stops" must be <= ${MAX_STOPS}, but got ${JSON.stringify(st
Error message
"stops" must be <= ${MAX_STOPS}, but got ${JSON.stringify(stops)} What it means
Thrown by validateExposureParams() in exposure.ts when the resolved `stops` value exceeds MAX_STOPS (5). It is a TypeError raised during validateParams, before WebGL setup, giving deterministic feedback. The value is JSON-stringified into the message.
Source
Thrown at packages/effects/src/exposure.ts:62
};
const resolve = (params: ExposureParams): ExposureResolved => ({
stops: params.stops ?? DEFAULT_STOPS,
});
const validateExposureParams = (params: ExposureParams): void => {
assertEffectParamsObject(params, 'Exposure');
assertOptionalFiniteNumber(params.stops, 'stops');
const {stops} = resolve(params);
if (stops < MIN_STOPS) {
throw new TypeError(
`"stops" must be >= ${MIN_STOPS}, but got ${JSON.stringify(stops)}`,
);
}
if (stops > MAX_STOPS) {
throw new TypeError(
`"stops" must be <= ${MAX_STOPS}, but got ${JSON.stringify(stops)}`,
);
}
};
const VERTEX_SHADER = /* glsl */ `#version 300 es
in vec2 aPos;
in vec2 aUv;
out vec2 vUv;
void main() {
vUv = aUv;
gl_Position = vec4(aPos, 0.0, 1.0);
}
`;
const FRAGMENT_SHADER = /* glsl */ `#version 300 es
precision highp float;View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Clamp to the documented range before calling: exposure({ stops: Math.max(-5, Math.min(5, value)) }).
- Replace overshooting interpolation (spring/bounce) with an easing that respects the [−5, 5] bounds.
- Constrain upstream input (data file, schema, slider) so stops can never exceed 5.
- Stack multiple exposure() effects if a larger combined shift is required.
Example fix
// before
exposure({ stops: animatedValue }); // animatedValue peaks at 6.2 -> throws
// after
exposure({ stops: Math.min(5, Math.max(-5, animatedValue)) }); Defensive patterns
Strategy: validation
Validate before calling
const EXPOSURE_STOPS_MIN = -5;
const EXPOSURE_STOPS_MAX = 5;
const clampStops = (stops: number): number =>
Math.max(EXPOSURE_STOPS_MIN, Math.min(EXPOSURE_STOPS_MAX, stops));
// usage: exposure({ stops: clampStops(animatedValue) }) Type guard
const isExposureStops = (v: unknown): v is number =>
typeof v === 'number' &&
Number.isFinite(v) &&
v >= -5 &&
v <= 5;
// guard: if (isExposureStops(value)) exposure({ stops: value }); else /* clamp or skip */ Prevention
- Clamp animated stops to [-5, 5] at the source (interpolate with extrapolateLeft/Right: 'clamp').
- Avoid overshooting easings (spring/bounce) on stops.
- Constrain upstream data and UI so stops can never exceed 5.
- Unit-test the stops stream against the [-5, 5] bounds.
When it happens
Trigger: Calling exposure({ stops: x }) with x > 5 (e.g. exposure({ stops: 8 })). Because resolve() only defaults undefined to 0, any explicitly provided number above 5 reaches this branch and throws.
Common situations: Easing curves that overshoot past +5 (springs are a common culprit); data-driven stops from a config with no upper bound; composing exposures additively and assuming the effect clamps; UI controls allowing values beyond the documented ±5.
Related errors
- "stops" must be >= ${MIN_STOPS}, but got ${JSON.stringify(st
- "exposure" must be >= ${MIN_EXPOSURE}, but got ${JSON.string
- "exposure" must be <= ${MAX_EXPOSURE}, but got ${JSON.string
- "${name}" must be >= 1
- "${name}" must be greater than 0, but got ${JSON.stringify(v
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/4ca01b24482c0d67.
Report an issue: GitHub.