remotion-dev/remotion · error · TypeError

"${name}" must be an integer, but got ${JSON.stringify(value

Error message

"${name}" must be an integer, but got ${JSON.stringify(value)}

What it means

pattern() rejects non-integer values for props that are semantically whole-pixel counters (the row/column offset 'every' divisors and similar integer-step fields). assertOptionalInteger throws when such a prop is defined but not an integer, so fractional values cannot silently corrupt the tiling math.

Source

Thrown at packages/effects/src/pattern.ts:241

		return;
	}

	if (
		!Array.isArray(value) ||
		value.length !== 2 ||
		value.some((item) => typeof item !== 'number' || !Number.isFinite(item))
	) {
		throw new TypeError(`"${name}" must be a [number, number] tuple`);
	}
};

const assertOptionalInteger = (value: unknown, name: string): void => {
	if (value === undefined) {
		return;
	}

	if (!Number.isInteger(value)) {
		throw new TypeError(
			`"${name}" must be an integer, but got ${JSON.stringify(value)}`,
		);
	}
};

const validatePositive = (value: number, name: string): void => {
	if (value <= 0) {
		throw new TypeError(`"${name}" must be > 0`);
	}
};

const validateAtLeast = (value: number, min: number, name: string): void => {
	if (value < min) {
		throw new TypeError(
			`"${name}" must be >= ${min}, but got ${JSON.stringify(value)}`,
		);
	}
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Round the value before passing: Math.round(x) or Math.trunc(x).
  2. Use the prop only where a fractional value is allowed (offsetU/offsetV accept floats); keep integer fields whole.
  3. Coerce untyped config inputs with Number() then validate with Number.isInteger yourself first.

Example fix

// before
pattern({ rowOffsetEvery: 2.5 })

// after
pattern({ rowOffsetEvery: Math.round(animatedEvery) })
Defensive patterns

Strategy: validation

Validate before calling

// Validate integer props before calling pattern().
function asInt(v: unknown, name: string): number | undefined {
  if (v === undefined) return undefined;
  const n = Number(v);
  if (!Number.isInteger(n)) throw new Error(`${name} must be an integer`);
  return n;
}
pattern({
  rowOffsetEvery: asInt(raw.rowOffsetEvery, 'rowOffsetEvery'),
  columnOffsetEvery: asInt(raw.columnOffsetEvery, 'columnOffsetEvery'),
});

Type guard

const isOptionalInteger = (v: unknown): v is number =>
  v === undefined || (typeof v === 'number' && Number.isInteger(v));

Prevention

When it happens

Trigger: Calling pattern() with rowOffsetEvery, columnOffsetEvery, rowOffset, columnOffset, gapX, gapY, or a crop prop set to a non-integer such as 2.5, or a numeric string like '3'. Validation runs in validatePatternParams before the effect renders.

Common situations: Driving integer props from a slider/animation that produces fractional values; reading counts from computed floats without rounding; passing strings from URL/config params.

Related errors


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