remotion-dev/remotion · error · TypeError

"exposure" must be <= ${MAX_EXPOSURE}, but got ${JSON.string

Error message

"exposure" must be <= ${MAX_EXPOSURE}, but got ${JSON.stringify(resolved.exposure)}

What it means

Thrown by validateColorCorrectionParams when the resolved exposure value exceeds MAX_EXPOSURE (5). Exposure is in stops and the schema caps it at 5; anything above is rejected with a TypeError showing the offending value. This is a caller-input error.

Source

Thrown at packages/effects/src/color-correction.ts:175

	assertOptionalFiniteNumber(params.pivot, 'pivot');
	assertOptionalFiniteNumber(params.shadows, 'shadows');
	assertOptionalFiniteNumber(params.highlights, 'highlights');
	assertOptionalFiniteNumber(params.whites, 'whites');
	assertOptionalFiniteNumber(params.blacks, 'blacks');
	assertOptionalFiniteNumber(params.temperature, 'temperature');
	assertOptionalFiniteNumber(params.tint, 'tint');
	assertOptionalFiniteNumber(params.saturation, 'saturation');
	assertOptionalFiniteNumber(params.vibrance, 'vibrance');

	const resolved = resolve(params);
	if (resolved.exposure < MIN_EXPOSURE) {
		throw new TypeError(
			`"exposure" must be >= ${MIN_EXPOSURE}, but got ${JSON.stringify(resolved.exposure)}`,
		);
	}

	if (resolved.exposure > MAX_EXPOSURE) {
		throw new TypeError(
			`"exposure" must be <= ${MAX_EXPOSURE}, but got ${JSON.stringify(resolved.exposure)}`,
		);
	}

	validateNonNegative(resolved.contrast, 'contrast');
	validateUnitInterval(resolved.pivot, 'pivot');
	validateSignedUnitInterval(resolved.shadows, 'shadows');
	validateSignedUnitInterval(resolved.highlights, 'highlights');
	validateSignedUnitInterval(resolved.whites, 'whites');
	validateSignedUnitInterval(resolved.blacks, 'blacks');
	validateSignedUnitInterval(resolved.temperature, 'temperature');
	validateSignedUnitInterval(resolved.tint, 'tint');
	validateNonNegative(resolved.saturation, 'saturation');
	validateSignedUnitInterval(resolved.vibrance, 'vibrance');
};

const VERTEX_SHADER = /* glsl */ `#version 300 es
in vec2 aPos;

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Clamp exposure to [-5, 5]: Math.max(-5, Math.min(5, value)).
  2. Use interpolate(..., {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'}) so animation cannot exceed the cap.
  3. Inspect the value in the error message and fix the producer of that number.
  4. Omit exposure to use the default of 0.

Example fix

// before
colorCorrection({exposure: 8}); // throws: must be <= 5

// after
const exposure = Math.max(-5, Math.min(5, springValue));
colorCorrection({exposure});
Defensive patterns

Strategy: validation

Validate before calling

const EXPOSURE_MIN = -5;
const EXPOSURE_MAX = 5;

function assertExposure(value: number | undefined): number | undefined {
  if (value === undefined) return value;
  if (!Number.isFinite(value)) {
    throw new TypeError(`exposure must be finite, got ${value}`);
  }
  if (value < EXPOSURE_MIN || value > EXPOSURE_MAX) {
    throw new TypeError(
      `exposure must be in [${EXPOSURE_MIN}, ${EXPOSURE_MAX}], got ${value}`,
    );
  }
  return value;
}

Type guard

const isExposure = (v: unknown): v is number =>
  typeof v === 'number' &&
  Number.isFinite(v) &&
  v >= -5 &&
  v <= 5;

Prevention

When it happens

Trigger: Calling colorCorrection({exposure: x}) where x > 5, evaluated at color-correction.ts:174 after the lower-bound check passes. Reached once exposure is confirmed finite and >= -5.

Common situations: Animated exposure from Spring/interpolate that overshoots above 5, a value ported from a different exposure scale, or a slider whose max exceeds 5.

Related errors


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