{"record":{"id":"085dd707f94d7ca5","repo":"remotion-dev/remotion","slug":"stops-must-be-min-stops-but-got-json-st","errorCode":null,"errorMessage":"\"stops\" must be >= ${MIN_STOPS}, but got ${JSON.stringify(stops)}","messagePattern":"\"stops\" must be >= (.+?), but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/exposure.ts","lineNumber":56,"sourceCode":"\treadonly vbo: WebGLBuffer;\n\treadonly textureSource: WebGLTexture;\n\treadonly uniforms: {\n\t\treadonly uSource: WebGLUniformLocation | null;\n\t\treadonly uStops: WebGLUniformLocation | null;\n\t};\n};\n\nconst resolve = (params: ExposureParams): ExposureResolved => ({\n\tstops: params.stops ?? DEFAULT_STOPS,\n});\n\nconst validateExposureParams = (params: ExposureParams): void => {\n\tassertEffectParamsObject(params, 'Exposure');\n\tassertOptionalFiniteNumber(params.stops, 'stops');\n\n\tconst {stops} = resolve(params);\n\tif (stops < MIN_STOPS) {\n\t\tthrow new TypeError(\n\t\t\t`\"stops\" must be >= ${MIN_STOPS}, but got ${JSON.stringify(stops)}`,\n\t\t);\n\t}\n\n\tif (stops > MAX_STOPS) {\n\t\tthrow new TypeError(\n\t\t\t`\"stops\" must be <= ${MAX_STOPS}, but got ${JSON.stringify(stops)}`,\n\t\t);\n\t}\n};\n\nconst VERTEX_SHADER = /* glsl */ `#version 300 es\nin vec2 aPos;\nin vec2 aUv;\nout vec2 vUv;\n\nvoid main() {\n\tvUv = aUv;","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/exposure.ts#L38-L74","documentation":"Thrown by validateExposureParams() in exposure.ts when the resolved `stops` value is below MIN_STOPS (-5). It is a TypeError fired during the effect's validateParams step, before any WebGL work, so the user gets fast, deterministic feedback. The offending value is JSON-stringified into the message.","triggerScenarios":"Calling exposure({ stops: x }) with x < -5 (e.g. exposure({ stops: -6 }), or a NaN that slipped past assertOptionalFiniteNumber only if the finite-number guard was bypassed). Resolution applies the DEFAULT_STOPS (0) only when stops is undefined; any provided number below -5 trips this branch.","commonSituations":"Animations interpolating stops with a curve that overshoots past -5 (e.g. an easing that briefly hits -5.5); reading stops from a data file or control that allows out-of-range values; passing a negativeInfinity by mistake; UI slider with a wider range than the schema enforces.","solutions":["Clamp the animated value to [-5, 5] before passing it: exposure({ stops: Math.max(-5, Math.min(5, value)) }).","Inspect the easing/interpolation for overshoot and pick an easing that stays in range (e.g. linear or ease-in-out without spring overshoot).","Validate the source data feeding stops and reject or clamp values outside [-5, 5] upstream.","If you genuinely need more than ±5 stops, layer two exposure() effects or request a wider range from the effect maintainer."],"exampleFix":"// before\nexposure({ stops: springValue }); // spring overshoots to -5.4 -> throws\n\n// after\nexposure({ stops: Math.max(-5, Math.min(5, springValue)) });","handlingStrategy":"validation","validationCode":"// Clamp before passing to exposure(); range is [-5, 5] (MIN_STOPS..MAX_STOPS).\nconst EXPOSURE_STOPS_MIN = -5;\nconst EXPOSURE_STOPS_MAX = 5;\n\nconst clampStops = (stops: number): number =>\n  Math.max(EXPOSURE_STOPS_MIN, Math.min(EXPOSURE_STOPS_MAX, stops));\n\n// usage: exposure({ stops: clampStops(animatedValue) })","typeGuard":"const isExposureStops = (v: unknown): v is number =>\n  typeof v === 'number' &&\n  Number.isFinite(v) &&\n  v >= -5 &&\n  v <= 5;\n\n// guard: if (isExposureStops(value)) exposure({ stops: value }); else /* clamp or skip */","tryCatchPattern":null,"preventionTips":["Clamp animated stops to [-5, 5] at the source (e.g. interpolate with extrapolateLeft/Right: 'clamp').","Avoid spring/bounce easing on stops; they overshoot past the bounds.","Constrain upstream data (config, schema, UI slider) so stops can never be below -5.","Run a unit test asserting your stops stream stays within [-5, 5]."],"tags":["validation","exposure","params","stops","range","typescript"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}