{"record":{"id":"32ac0177d1f1e1ea","repo":"remotion-dev/remotion","slug":"forcetranscode-must-be-a-boolean","errorCode":null,"errorMessage":"forceTranscode must be a boolean.","messagePattern":"forceTranscode must be a boolean\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/video-matting/src/prepare-audio.ts","lineNumber":74,"sourceCode":"\taudioQuality: Quality | null;\n\tforceTranscode: boolean;\n}): Promise<PreparedVideoMattingAudio> => {\n\tif (!Number.isFinite(videoStartTimestamp)) {\n\t\tthrow new TypeError('videoStartTimestamp must be a finite number.');\n\t}\n\n\tif (!Number.isFinite(videoEndTimestamp)) {\n\t\tthrow new TypeError('videoEndTimestamp must be a finite number.');\n\t}\n\n\tif (videoEndTimestamp < videoStartTimestamp) {\n\t\tthrow new RangeError(\n\t\t\t'videoEndTimestamp must be greater than or equal to videoStartTimestamp.',\n\t\t);\n\t}\n\n\tif (typeof forceTranscode !== 'boolean') {\n\t\tthrow new TypeError('forceTranscode must be a boolean.');\n\t}\n\n\tif (destination === 'none') {\n\t\treturn {\n\t\t\tprime: () => Promise.resolve(),\n\t\t\twriteAudioUntil: () => Promise.resolve(),\n\t\t\tfinishAudio: () => Promise.resolve(),\n\t\t\tcancel: () => Promise.resolve(),\n\t\t};\n\t}\n\n\tconst audioTrack = await input.getPrimaryAudioTrack();\n\tif (audioTrack === null) {\n\t\treturn {\n\t\t\tprime: () => Promise.resolve(),\n\t\t\twriteAudioUntil: () => Promise.resolve(),\n\t\t\tfinishAudio: () => Promise.resolve(),\n\t\t\tcancel: () => Promise.resolve(),","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/video-matting/src/prepare-audio.ts#L56-L92","documentation":"prepareAudio() requires the forceTranscode option to be a boolean if supplied. This guard (a TypeError) ensures the internal option parsing never receives strings, undefined-as-string, or other coercible values that would silently change transcoding behavior. The check happens after video timestamp validation and before deciding whether the 'none' destination returns a no-op pipeline.","triggerScenarios":"Calling prepareAudio({forceTranscode: 'true'}), forceTranscode: 1, or forceTranscode: null — any value whose typeof is not 'boolean'.","commonSituations":"Passing the value through from CLI args, query strings, or JSON where booleans arrive as strings; forgetting that forceTranscode is not optional-string; hand-editing config files without converting the type.","solutions":["Pass an actual boolean: forceTranscode: true or forceTranscode: false.","If the value comes from user input, coerce with === 'true' comparison or omit the property entirely when not needed.","Omit the forceTranscode key instead of passing null or undefined wrapped in a string."],"exampleFix":"// before\nawait prepareAudio({input, forceTranscode: 'true'});\n// after\nawait prepareAudio({input, forceTranscode: true});","handlingStrategy":"type-guard","validationCode":"if (forceTranscode !== undefined && typeof forceTranscode !== 'boolean') throw new TypeError('forceTranscode must be boolean');","typeGuard":"const isBool = (v: unknown): v is boolean => typeof v === 'boolean';","tryCatchPattern":"try { await prepareAudio(opts); } catch (e) { if (e instanceof TypeError && /forceTranscode/.test(e.message)) { opts.forceTranscode = opts.forceTranscode === 'true'; return prepareAudio(opts); } throw e; }","preventionTips":["Coerce string inputs with === 'true' before passing","Omit the key rather than passing null","Type the options object as PrepareAudioOptions so TS catches non-boolean values"],"tags":["typeerror","validation","options"],"backgroundTag":"invalid-argument-value","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}