{"record":{"id":"91ce928164c338d6","repo":"remotion-dev/remotion","slug":"fps-must-be-a-number-but-you-passed-a-value-of","errorCode":null,"errorMessage":"\"fps\" must be a number, but you passed a value of type ${typeof fps} ${location}","messagePattern":"\"fps\" must be a number, but you passed a value of type (.+?) (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/validation/validate-fps.ts","lineNumber":7,"sourceCode":"export function validateFps(\n\tfps: unknown,\n\tlocation: string,\n\tisGif: boolean,\n): asserts fps is number {\n\tif (typeof fps !== 'number') {\n\t\tthrow new Error(\n\t\t\t`\"fps\" must be a number, but you passed a value of type ${typeof fps} ${location}`,\n\t\t);\n\t}\n\n\tif (!Number.isFinite(fps)) {\n\t\tthrow new Error(\n\t\t\t`\"fps\" must be a finite, but you passed ${fps} ${location}`,\n\t\t);\n\t}\n\n\tif (isNaN(fps)) {\n\t\tthrow new Error(`\"fps\" must not be NaN, but got ${fps} ${location}`);\n\t}\n\n\tif (fps <= 0) {\n\t\tthrow new TypeError(`\"fps\" must be positive, but got ${fps} ${location}`);\n\t}\n","sourceCodeStart":1,"sourceCodeEnd":25,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/validation/validate-fps.ts#L1-L25","documentation":"Remotion validates the `fps` value of a composition or video config via `validateFps()` before it is used. This specific branch fires when the value passed as `fps` is not of type `number` (e.g. a string from CLI parsing, `undefined`, or `null`). The `${location}` placeholder in the message is filled with a human-readable hint of where the bad value originated (e.g. the composition id or 'the `fps` prop').","triggerScenarios":"Passing `fps` as a non-number to a `<Composition fps={...}>`, `useVideoConfig()`, `resolveVideoConfig()`, or any config-building call that routes through `validateFps`. Typical offenders: `fps=\"30\"` (string), `fps={null}`, `fps={undefined}`, or a value read from a JSON/env file that was not coerced.","commonSituations":"Reading fps from an environment variable or JSON config file (always strings), deserializing a composition config from a server payload, or passing a CSS-unit string like `\"30fps\"`.","solutions":["Ensure `fps` is a literal number, e.g. `fps={30}`.","If loading fps from env/JSON, coerce explicitly: `fps={Number(process.env.REMOTION_FPS)}`.","Add a runtime guard before constructing the composition: `if (typeof fps !== 'number') throw ...`.","Check the `${location}` segment of the error to find which composition or prop is at fault."],"exampleFix":"// before\n<Composition fps=\"30\" ... />\n// after\n<Composition fps={30} ... />","handlingStrategy":"validation","validationCode":"function assertFps(fps: unknown, location: string): void {\n  if (typeof fps !== 'number') {\n    throw new Error(`Invalid fps at ${location}: expected number, got ${typeof fps}`);\n  }\n}\nassertFps(myFps, 'my-comp');","typeGuard":"const isNumber = (v: unknown): v is number => typeof v === 'number';","tryCatchPattern":null,"preventionTips":["Type fps as `number` in all config helpers.","Coerce env/JSON values with `Number(...)` at the boundary.","Never accept `string | number` for fps in shared utilities."],"tags":["validation","config","typescript","fps"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}