{"record":{"id":"278009622e6a947e","repo":"remotion-dev/remotion","slug":"scale-must-be-greater-than-0-but-got-json-str-278009","errorCode":null,"errorMessage":"\"scale\" must be greater than 0, but got ${JSON.stringify(r.scale)}","messagePattern":"\"scale\" must be greater than 0, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/roughen-edges.ts","lineNumber":123,"sourceCode":"\t\tthrow new TypeError(\n\t\t\t`\"${name}\" must be <= ${max}, but got ${JSON.stringify(value)}`,\n\t\t);\n\t}\n};\n\nconst validateRoughenEdgesParams = (params: RoughenEdgesParams): void => {\n\tassertEffectParamsObject(params, 'Roughen edges');\n\tassertOptionalFiniteNumber(params.amount, 'amount');\n\tassertOptionalFiniteNumber(params.border, 'border');\n\tassertOptionalFiniteNumber(params.scale, 'scale');\n\tassertOptionalFiniteNumber(params.seed, 'seed');\n\n\tconst r = resolve(params);\n\tvalidateUnitInterval(r.amount, 'amount');\n\tvalidateNonNegative(r.border, 'border');\n\tvalidateAtMost(r.border, MAX_BORDER, 'border');\n\tif (r.scale <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`\"scale\" must be greater than 0, but got ${JSON.stringify(r.scale)}`,\n\t\t);\n\t}\n\n\tvalidateAtMost(r.scale, 4, 'scale');\n\tvalidateNonNegative(r.seed, 'seed');\n\tvalidateAtMost(r.seed, MAX_SEED, 'seed');\n};\n\nconst ROUGHEN_EDGES_VS = /* glsl */ `#version 300 es\nin vec2 aPos;\nin vec2 aUv;\nout vec2 vUv;\n\nvoid main() {\n\tvUv = aUv;\n\tgl_Position = vec4(aPos, 0.0, 1.0);\n}","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/roughen-edges.ts#L105-L141","documentation":"Thrown by the `roughenEdges()` effect when the resolved `scale` is less than or equal to 0. `scale` controls the frequency of the edge noise pattern; the shader divides by `uScale` (clamped to 0.001 internally), so a non-positive scale is rejected up front. Note the upper bound (4) is enforced separately by `validateAtMost`, so this error specifically means `scale <= 0`.","triggerScenarios":"Call `roughenEdges({scale: 0})` or `roughenEdges({scale: -0.5})`; animate `scale` through zero with `interpolate(frame, [0, 30], [0.5, -0.5])`; derive `scale` from a subtraction that can reach zero.","commonSituations":"Treating `scale` as a signed parameter (it is strictly positive, range 0.01–4); crossfading two scales through zero; passing a default-zero value from another effect's prop.","solutions":["Use a positive value within [0.01, 4], e.g. `scale: 0.07` (the default).","Clamp animated values with `Math.max(0.01, value)` or `interpolate(..., {extrapolateLeft: 'clamp'})`.","Omit `scale` to use the default of 0.07."],"exampleFix":"// before\nroughenEdges({scale: interpolate(frame, [0, 30], [0.5, -0.5])});\n// after\nroughenEdges({\n  scale: interpolate(frame, [0, 30], [0.5, 0.01], {extrapolateRight: 'clamp'}),\n});","handlingStrategy":"validation","validationCode":"const validateRoughenScale = (scale: unknown): number => {\n  if (typeof scale !== 'number' || !Number.isFinite(scale) || scale <= 0) {\n    throw new TypeError(`scale must be a finite number > 0, got ${String(scale)}`);\n  }\n  return Math.min(4, scale); // enforce upper bound too\n};\n\nroughenEdges({scale: validateRoughenScale(myScale)});","typeGuard":"const isValidRoughenScale = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v > 0 && v <= 4;","tryCatchPattern":null,"preventionTips":["Treat `scale` as strictly positive (range 0.01–4) in your own types.","Clamp animated `scale` with `Math.max(0.01, value)` or `extrapolateLeft: 'clamp'`.","Avoid crossfading scales through zero."],"tags":["validation","roughen-edges-effect","effects","typescript","params"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}