{"record":{"id":"d414cc3c8abc2237","repo":"remotion-dev/remotion","slug":"expiresin-should-be-an-integer-but-is-json-str","errorCode":null,"errorMessage":"'expiresIn' should be an integer but is ${JSON.stringify(presignExpiration)}","messagePattern":"'expiresIn' should be an integer but is (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/lambda-client/src/validate-presign-expiration.ts","lineNumber":28,"sourceCode":"\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(\n\t\t\t`The 'expiresIn' parameter must be less or equal than ${MAX_PRESIGN_EXPIRATION} (7 days) as enforced by AWS`,\n\t\t);\n\t}\n\n\tif (presignExpiration < MIN_PRESIGN_EXPIRATION) {\n\t\tthrow new TypeError(\n\t\t\t`The 'expiresIn' parameter must be greater or equal than ${MIN_PRESIGN_EXPIRATION}`,\n\t\t);\n\t}\n};","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/lambda-client/src/validate-presign-expiration.ts#L10-L46","documentation":"Thrown by validatePresignExpiration() when expiresIn is a finite number but not an integer. AWS presigned URL TTLs are measured in whole seconds; fractional seconds are not accepted by the signing logic.","triggerScenarios":"Passing expiresIn: 3600.5, or any value computed from a division that yields a decimal (e.g. minutes * 60.005).","commonSituations":"A UI that lets users enter fractional seconds; unit conversion that introduces floating-point error (hoursToSeconds = hours * 3600 producing 3599.9999).","solutions":["Round the value: Math.round(expiresIn).","For unit conversions, round after multiplication to kill float drift.","If accepting minutes/hours from users, convert to integer seconds explicitly."],"exampleFix":"// before\nconst expiresIn = hours * 3600.5; // fractional\nawait renderMediaOnLambda({..., opts: {expiresIn}});\n\n// after\nconst expiresIn = Math.round(hours * 3600);\nawait renderMediaOnLambda({..., opts: {expiresIn}});","handlingStrategy":"validation","validationCode":"const expiresIn = Math.round(Number(input));","typeGuard":"const isIntegerExpiresIn = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v % 1 === 0;","tryCatchPattern":null,"preventionTips":["Round after any floating-point unit conversion.","Express user-facing TTLs in minutes/hours and convert to integer seconds internally.","Use zod .int() or JSON schema integer for config."],"tags":["lambda","validation","typescript","presign"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}