{"record":{"id":"1a90cff42d9f7f08","repo":"remotion-dev/remotion","slug":"preservepitch-must-be-a-boolean-or-undefined-but","errorCode":null,"errorMessage":"'preservePitch' must be a boolean or undefined but got '${typeof props.preservePitch}' instead","messagePattern":"'preservePitch' must be a boolean or undefined but got '(.+?)' instead","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/validate-media-props.ts","lineNumber":51,"sourceCode":"\t\t);\n\t}\n\n\tif (\n\t\ttypeof props.playbackRate === 'number' &&\n\t\t(isNaN(props.playbackRate) ||\n\t\t\t!Number.isFinite(props.playbackRate) ||\n\t\t\tprops.playbackRate <= 0)\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`You have passed a playbackRate of ${props.playbackRate} to your <${component} /> component. Playback rate must be a real number above 0.`,\n\t\t);\n\t}\n\n\tif (\n\t\ttypeof props.preservePitch !== 'boolean' &&\n\t\ttypeof props.preservePitch !== 'undefined'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`'preservePitch' must be a boolean or undefined but got '${typeof props.preservePitch}' instead`,\n\t\t);\n\t}\n};\n","sourceCodeStart":33,"sourceCodeEnd":56,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/validate-media-props.ts#L33-L56","documentation":"The <Audio>, <Video>, <Html5Video>, and <Html5Audio> components accept a `preservePitch` boolean prop that controls whether the audio pitch is preserved when `playbackRate` is not 1 (it maps to the HTML5 media element's preservesPitch feature). validateMediaProps rejects any value that is not a boolean or undefined so the underlying media element always receives a well-typed flag. This guards against silent coercion bugs where a truthy non-boolean would behave unexpectedly.","triggerScenarios":"Passing preservePitch as a string (\"true\", \"false\", \"yes\"), a number (0/1), or any object to <Audio>/<Video>/<Html5Video>/<Html5Audio>. Common when the prop is read from JSON/config files, URL query params, or API responses where booleans get stringified.","commonSituations":"Reading playback settings from a JSON config or environment variable that returns \"true\" as a string; spreading untyped props fetched from an API into a <Video> component; migrating from a custom player that used 1/0 for pitch flags.","solutions":["Pass preservePitch as a literal boolean or omit it: preservePitch={true} or preservePitch={false}.","If the value comes from a string source, coerce explicitly before rendering: preservePitch={String(val).toLowerCase() === 'true'}.","If the value comes from a number (0/1), convert: preservePitch={Boolean(numVal)}.","Omit the prop entirely to accept the default (undefined, which lets the browser default apply)."],"exampleFix":"// before\n<Video src={src} playbackRate={2} preservePitch=\"true\" />\n// after\n<Video src={src} playbackRate={2} preservePitch={true} />","handlingStrategy":"type-guard","validationCode":"if (preservePitch !== undefined && typeof preservePitch !== 'boolean') {\n  throw new Error(`preservePitch must be boolean or undefined, got ${typeof preservePitch}`);\n}","typeGuard":"const isPreservePitch = (v: unknown): v is boolean | undefined =>\n  v === undefined || typeof v === 'boolean';","tryCatchPattern":null,"preventionTips":["Type the prop as boolean | undefined in your own wrapper component so the compiler rejects strings/numbers.","When reading preservePitch from JSON/env, coerce with === 'true' rather than passing the raw string.","Never spread untyped API responses directly onto <Video>/<Audio>; map fields explicitly."],"tags":["validation","audio","video","props","typeerror","html5"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}