{"record":{"id":"08e247d9f0d1bdf7","repo":"remotion-dev/remotion","slug":"name-must-be-a-boolean-but-got-json-string","errorCode":null,"errorMessage":"\"${name}\" must be a boolean, but got ${JSON.stringify(value)}","messagePattern":"\"(.+?)\" must be a boolean, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/effects/src/dot-grid.ts","lineNumber":65,"sourceCode":"type DotGridResolved = {\n\tdotSize: number;\n\tgridSize: number;\n\tinvert: boolean;\n};\n\nconst resolve = (p: DotGridParams): DotGridResolved => ({\n\tdotSize: p.dotSize ?? DEFAULT_DOT_SIZE,\n\tgridSize: p.gridSize ?? DEFAULT_GRID_SIZE,\n\tinvert: p.invert ?? DEFAULT_INVERT,\n});\n\nconst assertOptionalBoolean = (value: unknown, name: string): void => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\n\tif (typeof value !== 'boolean') {\n\t\tthrow new TypeError(\n\t\t\t`\"${name}\" must be a boolean, but got ${JSON.stringify(value)}`,\n\t\t);\n\t}\n};\n\nconst validatePositive = (value: number, name: string): void => {\n\tif (value <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`\"${name}\" must be greater than 0, but got ${JSON.stringify(value)}`,\n\t\t);\n\t}\n};\n\nconst validateDotGridParams = (params: DotGridParams): void => {\n\tassertEffectParamsObject(params, 'Dot grid');\n\tassertOptionalFiniteNumber(params.dotSize, 'dotSize');\n\tassertOptionalFiniteNumber(params.gridSize, 'gridSize');\n\tassertOptionalBoolean(params.invert, 'invert');","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/dot-grid.ts#L47-L83","documentation":"Thrown by the dot-grid effect's assertOptionalBoolean guard when the invert prop is supplied but is not a boolean. invert toggles whether dots become holes versus filled circles in the fragment shader, and because it is uploaded to a bool uniform, the runtime demands an actual boolean. Truthy/falsy values like 'true', 1, 0, or null are rejected.","triggerScenarios":"Calling dotGrid() with invert: 'true' (string), invert: 1 or invert: 0 (number), invert: null, or invert: 'yes'. Also triggered by deserializing params from JSON where booleans were stored as 0/1 integers, or by binding invert to a schema that yields a string enum.","commonSituations":"Reading invert from a query string or env var (always strings); pulling config from YAML/TOML that coerces booleans; reusing a numeric toggle from another part of the app; animating invert with a Spring that interpolates to a fractional number.","solutions":["Pass a literal boolean: invert: true or invert: false.","Coerce at the boundary: invert: String(raw) === 'true', or invert: Boolean(raw).","If animating, drive invert from an interpolate() threshold that returns a boolean via a conditional, not a numeric spring value.","Omit invert to accept the default (false)."],"exampleFix":"// before\ndotGrid({invert: 'true', gridSize: 24});\n\n// after\ndotGrid({invert: String(process.env.INVERT) === 'true', gridSize: 24});","handlingStrategy":"type-guard","validationCode":"const invert = raw == null ? undefined : String(raw) === 'true';\n// then pass invert only when defined\ndotGrid(invert === undefined ? {} : {invert});","typeGuard":"const isOptionalBoolean = (v: unknown): v is boolean | undefined =>\n  v === undefined || typeof v === 'boolean';\n\nconst assertDotGridInvert = (v: unknown): boolean | undefined => {\n  if (!isOptionalBoolean(v)) {\n    throw new TypeError(`invert must be a boolean, got ${typeof v}`);\n  }\n  return v;\n};","tryCatchPattern":null,"preventionTips":["Coerce booleans at every external boundary (env vars, query strings, YAML/TOML) with Boolean(...) or String(x) === 'true'.","Type the prop as boolean | undefined in your own wrappers so TypeScript rejects strings/numbers.","Do not drive invert from a numeric Spring; derive a boolean via a threshold instead."],"tags":["validation","dot-grid","boolean","input-validation"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}