remotion-dev/remotion · error · TypeError

"scale" must be greater than 0, but got ${JSON.stringify(r.s

Error message

"scale" must be greater than 0, but got ${JSON.stringify(r.scale)}

What it means

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`.

Source

Thrown at packages/effects/src/roughen-edges.ts:123

		throw new TypeError(
			`"${name}" must be <= ${max}, but got ${JSON.stringify(value)}`,
		);
	}
};

const validateRoughenEdgesParams = (params: RoughenEdgesParams): void => {
	assertEffectParamsObject(params, 'Roughen edges');
	assertOptionalFiniteNumber(params.amount, 'amount');
	assertOptionalFiniteNumber(params.border, 'border');
	assertOptionalFiniteNumber(params.scale, 'scale');
	assertOptionalFiniteNumber(params.seed, 'seed');

	const r = resolve(params);
	validateUnitInterval(r.amount, 'amount');
	validateNonNegative(r.border, 'border');
	validateAtMost(r.border, MAX_BORDER, 'border');
	if (r.scale <= 0) {
		throw new TypeError(
			`"scale" must be greater than 0, but got ${JSON.stringify(r.scale)}`,
		);
	}

	validateAtMost(r.scale, 4, 'scale');
	validateNonNegative(r.seed, 'seed');
	validateAtMost(r.seed, MAX_SEED, 'seed');
};

const ROUGHEN_EDGES_VS = /* 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);
}

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Use a positive value within [0.01, 4], e.g. `scale: 0.07` (the default).
  2. Clamp animated values with `Math.max(0.01, value)` or `interpolate(..., {extrapolateLeft: 'clamp'})`.
  3. Omit `scale` to use the default of 0.07.

Example fix

// before
roughenEdges({scale: interpolate(frame, [0, 30], [0.5, -0.5])});
// after
roughenEdges({
  scale: interpolate(frame, [0, 30], [0.5, 0.01], {extrapolateRight: 'clamp'}),
});
Defensive patterns

Strategy: validation

Validate before calling

const validateRoughenScale = (scale: unknown): number => {
  if (typeof scale !== 'number' || !Number.isFinite(scale) || scale <= 0) {
    throw new TypeError(`scale must be a finite number > 0, got ${String(scale)}`);
  }
  return Math.min(4, scale); // enforce upper bound too
};

roughenEdges({scale: validateRoughenScale(myScale)});

Type guard

const isValidRoughenScale = (v: unknown): v is number =>
  typeof v === 'number' && Number.isFinite(v) && v > 0 && v <= 4;

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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