{"record":{"id":"3ba0ae23db72fc7c","repo":"remotion-dev/remotion","slug":"invalid-channel-index-channelindex-for-audio-wi","errorCode":null,"errorMessage":"Invalid channel index ${channelIndex} for audio with ${audioTrack.numberOfChannels} channels","messagePattern":"Invalid channel index (.+?) for audio with (.+?) channels","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-utils/src/use-windowed-audio-data.ts","lineNumber":157,"sourceCode":"\t\t\t\t\t\t\tsrc,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (await audioTrack.isRelativeToUnixEpoch()) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: ' +\n\t\t\t\t\t\t\tsrc,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst canDecode = await audioTrack.canDecode();\n\n\t\t\t\tif (!canDecode) {\n\t\t\t\t\tthrow new Error('Audio track cannot be decoded');\n\t\t\t\t}\n\n\t\t\t\tif (channelIndex >= audioTrack.numberOfChannels || channelIndex < 0) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Invalid channel index ${channelIndex} for audio with ${audioTrack.numberOfChannels} channels`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst numberOfChannels = await audioTrack.getNumberOfChannels();\n\t\t\t\tconst sampleRate = await audioTrack.getSampleRate();\n\n\t\t\t\tconst format = await input.getFormat();\n\n\t\t\t\tconst isMatroska = format === MATROSKA || format === WEBM;\n\n\t\t\t\tif (isMounted.current) {\n\t\t\t\t\tsetAudioUtils({\n\t\t\t\t\t\tinput,\n\t\t\t\t\t\ttrack: audioTrack,\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\tdurationInSeconds,\n\t\t\t\t\t\t\tnumberOfChannels,","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-utils/src/use-windowed-audio-data.ts#L139-L175","documentation":"Thrown inside useWindowedAudioData() when the requested channelIndex is out of range for the decoded audio track (line 156-160). The guard fires when channelIndex >= audioTrack.numberOfChannels or channelIndex < 0, and the message reports both the requested index and the actual channel count. Forwarded to cancelRender(), failing the render.","triggerScenarios":"Requesting channelIndex 1 (right) on a mono asset; requesting channel 5 on a stereo asset; passing -1 to mean 'auto'; defaulting to a high channel index without checking the source; passing a 0-based index when the source only has 1 channel.","commonSituations":"Hard-coding channelIndex for a stereo visualization on a mono voiceover; letting a user pick a channel without clamping; copying example code that uses channelIndex 1 onto a mono recording; assets that were downmixed to mono during export without updating the component.","solutions":["Default channelIndex to 0 (mono-safe) unless you specifically need another channel, and clamp it to the actual track's numberOfChannels - 1.","Probe the asset's channel count first (ffprobe or Mediabunny) and pass a valid index based on that value.","For visualizations that need a specific channel, require/prefer stereo assets or fall back to channel 0 when fewer channels exist.","Add a runtime guard at the call site so an invalid index never reaches the hook."],"exampleFix":"// before (stereo-only code on a mono asset -> throws)\nuseWindowedAudioData({src, channelIndex: 1, ...});\n\n// after (clamp to available channels before passing)\nconst channels = await getAudioNumberOfChannels(src);\nconst channelIndex = Math.min(1, Math.max(0, channels - 1));\nuseWindowedAudioData({src, channelIndex, ...});","handlingStrategy":"validation","validationCode":"// Clamp channelIndex to the asset's actual channel count before calling the hook\nimport {execFileSync} from 'child_process';\n\nfunction getNumberOfAudioChannels(file: string): number {\n  const n = execFileSync('ffprobe', ['-v', 'error', '-select_streams', 'a:0', '-show_entries', 'stream=channels', '-of', 'csv=p=0', file], {encoding: 'utf8'}).trim();\n  return Number(n) || 1;\n}\n\nconst channels = getNumberOfAudioChannels(file);\nconst safeChannelIndex = Math.min(requestedChannel, Math.max(0, channels - 1));","typeGuard":"function isValidChannelIndex(index: number, channels: number): boolean {\n  return Number.isInteger(index) && index >= 0 && index < channels;\n}","tryCatchPattern":"// Forwarded to cancelRender(); wrap an ErrorBoundary and fall back to channel 0:\n// <ErrorBoundary fallback={<Waveform channelIndex={0} ... />}>\n//   <WindowedWaveform channelIndex={requested} ... />\n// </ErrorBoundary>","preventionTips":["Default channelIndex to 0 (mono-safe) unless you specifically need another channel.","Probe the asset's channel count and clamp the requested index to channels - 1.","Re-validate the index whenever the asset changes (different source = different channel count).","Treat an out-of-range index as a configuration error in your UI rather than passing it through."],"tags":["audio","validation","channel-index","mediabunny","render-failure"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}