remotion-dev/remotion · error · TypeError

'expiresIn' should be a number, but is ${JSON.stringify(pres

Error message

'expiresIn' should be a number, but is ${JSON.stringify(presignExpiration)}

What it means

Thrown by validatePresignExpiration() in @remotion/lambda-client when the optional `expiresIn` (presignExpiration) argument is defined, non-null, but not a number. The value controls how long a presigned render-output URL stays valid; it must be an integer number of seconds.

Source

Thrown at packages/lambda-client/src/validate-presign-expiration.ts:10

const MAX_PRESIGN_EXPIRATION = 604800;
const MIN_PRESIGN_EXPIRATION = 1;

export const validatePresignExpiration = (presignExpiration: unknown) => {
	if (typeof presignExpiration === 'undefined' || presignExpiration === null) {
		return;
	}

	if (typeof presignExpiration !== 'number') {
		throw new TypeError(
			`'expiresIn' should be a number, but is ${JSON.stringify(
				presignExpiration,
			)}`,
		);
	}

	if (Number.isNaN(presignExpiration)) {
		throw new TypeError(`'expiresIn' should not be NaN, but is NaN`);
	}

	if (!Number.isFinite(presignExpiration)) {
		throw new TypeError(
			`'expiresIn' should be finite but is ${presignExpiration}`,
		);
	}

	if (presignExpiration % 1 !== 0) {
		throw new TypeError(

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Coerce the value to a number before passing: Number(expiresIn) and check Number.isFinite().
  2. If the source is a string env var, parse it explicitly: parseInt(process.env.EXPIRES_IN, 10).
  3. Omit expiresIn entirely if you want the default rather than passing a string.

Example fix

// before
await renderMediaOnLambda({..., opts: {expiresIn: process.env.EXPIRES_IN}});

// after
const expiresIn = process.env.EXPIRES_IN ? parseInt(process.env.EXPIRES_IN, 10) : undefined;
await renderMediaOnLambda({..., opts: {expiresIn}});
Defensive patterns

Strategy: type-guard

Validate before calling

const expiresIn = typeof raw === 'string' ? parseInt(raw, 10) : raw;
const safeExpires = typeof expiresIn === 'number' && Number.isFinite(expiresIn) ? expiresIn : undefined;
await renderMediaOnLambda({..., opts: {expiresIn: safeExpires}});

Type guard

const isExpiresIn = (v: unknown): v is number =>
  (typeof v === 'undefined' || v === null) ? false : typeof v === 'number' && Number.isFinite(v) && v % 1 === 0 && v >= 1 && v <= 604800;

Prevention

When it happens

Trigger: Calling presignUrl() / renderMediaOnLambda() with expiresIn passed as a string (e.g. "3600" from an env var), a boolean, or an object. The undefined/null early-return means only other types trip this.

Common situations: Reading expiresIn from an environment variable or JSON config without Number() coercion; forwarding a query-string value (always a string) straight into the API.

Related errors


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