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
- Coerce the value to a number before passing: Number(expiresIn) and check Number.isFinite().
- If the source is a string env var, parse it explicitly: parseInt(process.env.EXPIRES_IN, 10).
- 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
- Coerce expiresIn from any string source (env var, query string, JSON) with parseInt/Number before passing.
- Pass undefined rather than a string when you want the library default.
- Centralize env-var parsing in one module that returns correctly-typed values.
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
- maxRetries must be a number, but is ${JSON.stringify(maxRetr
- parameter 'memorySizeInMb' must not be NaN, but is
- parameter 'memorySizeInMb' must be finite, but is ${memorySi
- parameter 'memorySizeInMb' must be an integer but got ${memo
- 'expiresIn' should not be NaN, but is NaN
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/ba32d582ffc659d9.
Report an issue: GitHub.