{"record":{"id":"773b9ab271ae5f65","repo":"remotion-dev/remotion","slug":"no-mp3-info-773b9a","errorCode":null,"errorMessage":"No MP3 info","messagePattern":"No MP3 info","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/mp3/seek/audio-sample-from-vbr.ts","lineNumber":21,"sourceCode":"import {WEBCODECS_TIMESCALE} from '../../../webcodecs-timescale';\nimport {getDurationFromMp3Xing} from '../get-duration';\nimport {getTimeFromPosition} from '../parse-xing';\nimport {getSamplesPerMpegFrame} from '../samples-per-mpeg-file';\nimport type {AudioSampleFromCbr} from './audio-sample-from-cbr';\n\nexport const getAudioSampleFromVbr = ({\n\tinfo,\n\tposition,\n\tmp3Info,\n\tdata,\n}: {\n\tposition: number;\n\tinfo: VariableMp3BitrateInfo;\n\tmp3Info: Mp3Info | null;\n\tdata: Uint8Array;\n}): AudioSampleFromCbr => {\n\tif (!mp3Info) {\n\t\tthrow new Error('No MP3 info');\n\t}\n\n\tconst samplesPerFrame = getSamplesPerMpegFrame({\n\t\tlayer: mp3Info.layer,\n\t\tmpegVersion: mp3Info.mpegVersion,\n\t});\n\tconst wholeFileDuration = getDurationFromMp3Xing({\n\t\tsamplesPerFrame,\n\t\txingData: info.xingData,\n\t});\n\tif (!info.xingData.fileSize) {\n\t\tthrow new Error('file size');\n\t}\n\n\tif (!info.xingData.tableOfContents) {\n\t\tthrow new Error('table of contents');\n\t}\n","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/mp3/seek/audio-sample-from-vbr.ts#L3-L39","documentation":"Thrown in getAudioSampleFromVbr() when the caller passes mp3Info === null. VBR seek math needs the layer/mpegVersion from mp3Info to compute samplesPerFrame and to interpret the Xing TOC. Unlike 1384 this is an explicit parameter, so a null means the upstream caller did not have MP3 info ready.","triggerScenarios":"Calling getAudioSampleFromVbr() without first obtaining mp3Info from the parser state, e.g. seeking before the first MP3 frame has been parsed, or wiring VBR seek into a code path where mp3Info is optional and unresolved.","commonSituations":"Early seek on a partially-loaded VBR MP3; integration code that did not gate the VBR seek on mp3Info availability.","solutions":["Gate the VBR seek on mp3Info being non-null: fetch/await parser state until getMp3Info() returns a value before calling getAudioSampleFromVbr().","Fall back to CBR seek when mp3Info is null.","Confirm the file is actually VBR MP3 with a valid Xing header so mp3Info gets populated."],"exampleFix":"// before\nconst sample = getAudioSampleFromVbr({info, position, mp3Info, data});\n\n// after\nif (!mp3Info) {\n  throw new Error('Cannot seek: mp3Info not yet available');\n}\nconst sample = getAudioSampleFromVbr({info, position, mp3Info, data});","handlingStrategy":"type-guard","validationCode":"// Require mp3Info before calling the VBR seek helper.\nif (!mp3Info) {\n  throw new Error('Cannot seek VBR: mp3Info not available');\n}\nconst sample = getAudioSampleFromVbr({info, position, mp3Info, data});","typeGuard":"function hasMp3Info(info: Mp3Info | null): info is Mp3Info {\n  return info != null;\n}","tryCatchPattern":"if (!mp3Info) {\n  // fall back to CBR seek or defer\n} else {\n  try {\n    const sample = getAudioSampleFromVbr({info, position, mp3Info, data});\n  } catch (err) {\n    if (!(err instanceof Error && err.message === 'No MP3 info')) throw err;\n  }\n}","preventionTips":["Never call getAudioSampleFromVbr with a null mp3Info — gate the call.","Wait for parser state to populate mp3Info before exposing seek to users.","Fall back to CBR seek when VBR info is missing."],"tags":["mp3","vbr","seek","media-parser"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}