{"record":{"id":"c8a070a13ef48f98","repo":"remotion-dev/remotion","slug":"name-must-be-an-integer-but-got-json-strin-c8a070","errorCode":null,"errorMessage":"\"${name}\" must be an integer, but got ${JSON.stringify(value)}","messagePattern":"\"(.+?)\" must be an integer, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/zoom-blur/index.ts","lineNumber":93,"sourceCode":"\t\treturn;\n\t}\n\n\tif (\n\t\t!Array.isArray(value) ||\n\t\tvalue.length !== 2 ||\n\t\tvalue.some((item) => typeof item !== 'number' || !Number.isFinite(item))\n\t) {\n\t\tthrow new TypeError(`\"${name}\" must be a [number, number] tuple`);\n\t}\n};\n\nconst assertOptionalInteger = (value: unknown, name: string): void => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\n\tif (!Number.isInteger(value)) {\n\t\tthrow new TypeError(\n\t\t\t`\"${name}\" must be an integer, but got ${JSON.stringify(value)}`,\n\t\t);\n\t}\n};\n\nconst validateZoomBlurParams = (params: ZoomBlurParams): void => {\n\tassertEffectParamsObject(params, 'Zoom Blur');\n\tassertOptionalFiniteNumber(params.amount, 'amount');\n\tassertOptionalUvCoordinate(params.center, 'center');\n\tassertOptionalFiniteNumber(params.samples, 'samples');\n\tassertOptionalInteger(params.samples, 'samples');\n\n\tconst r = resolve(params);\n\tvalidateNonNegative(r.amount, 'amount');\n\tvalidateUnitInterval(r.center[0], 'center[0]');\n\tvalidateUnitInterval(r.center[1], 'center[1]');\n\tif (r.samples < 1) {\n\t\tthrow new TypeError(","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/zoom-blur/index.ts#L75-L111","documentation":"The zoomBlur effect requires `samples` to be an integer when provided. This check (`assertOptionalInteger`) runs after the finite-number check but before range validation, catching fractional or non-integer sample counts. The value is optional (defaults to 24), but if present must be a whole number.","triggerScenarios":"Passing `samples: 24.5`, `samples: 12.1`, `samples: 1e0` is fine, but `samples: 3.14`, `samples: '24'` (string), or `samples: NaN` triggers it. Most commonly a UI slider with `step: 0.1` bound to the samples parameter.","commonSituations":"A numeric input or slider configured with a fractional step, arithmetic that produces floats (e.g., `amount / 2`), or animated values from interpolation that produce non-integer sample counts.","solutions":["Round the value before passing: `samples: Math.round(computedSamples)`.","Set the UI input step to 1 (integer) for the samples field.","Omit `samples` to use the default of 24."],"exampleFix":"// before\nzoomBlur({ samples: interpolatedValue }); // 23.7\n\n// after\nzoomBlur({ samples: Math.round(interpolatedValue) });","handlingStrategy":"validation","validationCode":"const samples = computedSamples;\nif (samples !== undefined && !Number.isInteger(samples)) {\n  throw new TypeError(`samples must be an integer, got ${samples}`);\n}\nzoomBlur({ samples });","typeGuard":"const isOptionalInteger = (v: unknown): v is number | undefined =>\n  v === undefined || (typeof v === 'number' && Number.isInteger(v));","tryCatchPattern":null,"preventionTips":["Round sample counts with Math.round before passing.","Set UI input step to 1 for integer-only fields.","Use TypeScript types that enforce integer at the source."],"tags":["validation","effects","zoom-blur","typescript"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}