{"record":{"id":"fe8bd06ec40d8966","repo":"remotion-dev/remotion","slug":"amplitude-must-be-0-but-got-json-stringify","errorCode":null,"errorMessage":"\"amplitude\" must be >= 0, but got ${JSON.stringify(resolved.amplitude)}","messagePattern":"\"amplitude\" must be >= 0, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/wave/index.ts","lineNumber":103,"sourceCode":"const validateWaveParams = (params: WaveParams): void => {\n\tassertEffectParamsObject(params, 'Wave');\n\tassertOptionalFiniteNumber(params.phase, 'phase');\n\tassertOptionalFiniteNumber(params.amplitude, 'amplitude');\n\tassertOptionalFiniteNumber(params.wavelength, 'wavelength');\n\n\tif (\n\t\tparams.direction !== undefined &&\n\t\tparams.direction !== 'horizontal' &&\n\t\tparams.direction !== 'vertical'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`\"direction\" must be \"horizontal\" or \"vertical\", but got ${JSON.stringify(params.direction)}`,\n\t\t);\n\t}\n\n\tconst resolved = resolve(params);\n\tif (resolved.amplitude < 0) {\n\t\tthrow new TypeError(\n\t\t\t`\"amplitude\" must be >= 0, but got ${JSON.stringify(resolved.amplitude)}`,\n\t\t);\n\t}\n\n\tif (resolved.wavelength <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`\"wavelength\" must be > 0, but got ${JSON.stringify(resolved.wavelength)}`,\n\t\t);\n\t}\n};\n\n// Sine wave warp: displaces source UVs along the propagation axis. WebGL2 only.\nexport const wave = createEffect<WaveParams, WaveState>({\n\ttype: 'dev.remotion.effects.wave',\n\tlabel: 'wave()',\n\tdocumentationLink: 'https://www.remotion.dev/docs/effects/wave',\n\tbackend: 'webgl2',\n\tcalculateKey: (params) => {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/wave/index.ts#L85-L121","documentation":"TypeError thrown by wave's validateWaveParams when the resolved amplitude is less than 0. Validation runs after the numeric finiteness check, so it only fires for a finite number outside the allowed range. Note the comparison uses the resolved value, so it also catches the case where amplitude is omitted... actually the default is 60, so it only triggers when an explicit negative number is passed.","triggerScenarios":"Calling wave({amplitude: -10}) or passing a computed value that goes negative (e.g. amplitude derived from a frame-based formula that dips below zero). assertOptionalFiniteNumber runs first, so non-numbers/NaN/Infinity are rejected earlier with a different message.","commonSituations":"Animation formulas that interpolate amplitude across frames and accidentally go negative; sign errors in derived values; passing a value intended for a different effect.","solutions":["Pass amplitude >= 0 (use Math.max(0, value) for derived values).","Clamp frame-driven amplitude with Math.abs() or Math.max(0, x) before passing it.","If you want 'no wave', use amplitude: 0 rather than a negative number.","Type amplitude as a non-negative number and assert it at the source."],"exampleFix":"// before - interpolated amplitude dips below zero\nconst e = wave({amplitude: Math.sin(frame / 10) * 100}); // negative half the time\n\n// after - clamp to the valid range\nconst e = wave({amplitude: Math.max(0, Math.sin(frame / 10) * 100)});","handlingStrategy":"validation","validationCode":"import {wave} from '@remotion/effects';\n\nconst clampAmplitude = (value: number): number => {\n  if (!Number.isFinite(value)) {\n    throw new TypeError(`amplitude must be a finite number, got ${value}`);\n  }\n  return Math.max(0, value);\n};\n\nconst amplitude = clampAmplitude(rawAmplitude);\nconst e = wave({amplitude, wavelength: 240});","typeGuard":"const isNonNegativeFinite = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v >= 0;","tryCatchPattern":"try {\n  const e = wave({amplitude: rawAmplitude, wavelength: 240});\n} catch (err) {\n  if (err instanceof TypeError) {\n    console.error('Invalid wave amplitude:', rawAmplitude, err);\n  }\n  throw err;\n}","preventionTips":["Clamp frame-derived amplitude with Math.max(0, value) before passing it.","Use amplitude: 0 to flatten the wave instead of a negative value.","Type amplitude as number and assert non-negativity at the source of derived values.","Watch interpolation/easing curves that can dip below zero."],"tags":["validation","params","wave","range"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}