{"record":{"id":"f53a529ee24938a0","repo":"remotion-dev/remotion","slug":"expiresin-should-not-be-nan-but-is-nan","errorCode":null,"errorMessage":"'expiresIn' should not be NaN, but is NaN","messagePattern":"'expiresIn' should not be NaN, but is NaN","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/lambda-client/src/validate-presign-expiration.ts","lineNumber":18,"sourceCode":"const MAX_PRESIGN_EXPIRATION = 604800;\nconst MIN_PRESIGN_EXPIRATION = 1;\n\nexport const validatePresignExpiration = (presignExpiration: unknown) => {\n\tif (typeof presignExpiration === 'undefined' || presignExpiration === null) {\n\t\treturn;\n\t}\n\n\tif (typeof presignExpiration !== 'number') {\n\t\tthrow new TypeError(\n\t\t\t`'expiresIn' should be a number, but is ${JSON.stringify(\n\t\t\t\tpresignExpiration,\n\t\t\t)}`,\n\t\t);\n\t}\n\n\tif (Number.isNaN(presignExpiration)) {\n\t\tthrow new TypeError(`'expiresIn' should not be NaN, but is NaN`);\n\t}\n\n\tif (!Number.isFinite(presignExpiration)) {\n\t\tthrow new TypeError(\n\t\t\t`'expiresIn' should be finite but is ${presignExpiration}`,\n\t\t);\n\t}\n\n\tif (presignExpiration % 1 !== 0) {\n\t\tthrow new TypeError(\n\t\t\t`'expiresIn' should be an integer but is ${JSON.stringify(\n\t\t\t\tpresignExpiration,\n\t\t\t)}`,\n\t\t);\n\t}\n\n\tif (presignExpiration > MAX_PRESIGN_EXPIRATION) {\n\t\tthrow new TypeError(","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/lambda-client/src/validate-presign-expiration.ts#L1-L36","documentation":"Thrown by validatePresignExpiration() when expiresIn is a number but equals NaN. Presigned URLs require a real TTL in seconds; AWS rejects NaN-derived signatures. The check runs after the typeof-number guard, so only a numeric NaN reaches it.","triggerScenarios":"Passing expiresIn: Number(someUnsetVar) (NaN), expiresIn: parseInt('abc', 10) (NaN), or any arithmetic that yields NaN.","commonSituations":"Env-var parse where the variable is empty/non-numeric; a formula like (a - b) where both are undefined producing NaN.","solutions":["Guard the parse with Number.isFinite() and fall back to undefined (let the library default) or a known good value.","Validate the source string with /^\\d+$/ before parseInt.","Skip passing expiresIn when the input is missing rather than forwarding NaN."],"exampleFix":"// before\nconst expiresIn = Number(process.env.EXPIRES_IN); // NaN\nawait renderMediaOnLambda({..., opts: {expiresIn}});\n\n// after\nconst raw = Number(process.env.EXPIRES_IN);\nconst expiresIn = Number.isFinite(raw) ? raw : undefined;\nawait renderMediaOnLambda({..., opts: {expiresIn}});","handlingStrategy":"type-guard","validationCode":"const raw = Number(process.env.EXPIRES_IN);\nconst expiresIn = Number.isFinite(raw) ? raw : undefined;","typeGuard":"const isValidExpiresIn = (v: unknown): v is number =>\n  typeof v === 'number' && !Number.isNaN(v) && Number.isFinite(v);","tryCatchPattern":null,"preventionTips":["Always pair Number() with Number.isFinite() when parsing external input.","Pass undefined to opt into the default instead of forwarding NaN.","Add a config-schema validator (e.g. zod) at app start."],"tags":["lambda","validation","typescript","presign"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}