{"record":{"id":"8545f6dd21eaa1ba","repo":"remotion-dev/remotion","slug":"no-mp3-info","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-cbr.ts","lineNumber":32,"sourceCode":"}: {\n\tbitrateInKbit: number;\n\tlayer: number;\n\tsamplesPerFrame: number;\n\tsampleRate: number;\n\tinitialOffset: number;\n\tdata: Uint8Array;\n\tstate: ParserState;\n}) => {\n\tconst avgLength = getAverageMpegFrameLength({\n\t\tbitrateKbit: bitrateInKbit,\n\t\tlayer,\n\t\tsamplesPerFrame,\n\t\tsamplingFrequency: sampleRate,\n\t});\n\n\tconst mp3Info = state.mp3.getMp3Info();\n\tif (!mp3Info) {\n\t\tthrow new Error('No MP3 info');\n\t}\n\n\tconst nthFrame = Math.round(\n\t\t(initialOffset - state.mediaSection.getMediaSectionAssertOnlyOne().start) /\n\t\t\tavgLength,\n\t);\n\n\tconst durationInSeconds = samplesPerFrame / sampleRate;\n\tconst timeInSeconds = (nthFrame * samplesPerFrame) / sampleRate;\n\t// Important that we round down, otherwise WebCodecs might stall, e.g.\n\t// Last input = 30570667 Last output = 30570666 -> stuck\n\tconst timestamp = Math.floor(timeInSeconds * WEBCODECS_TIMESCALE);\n\tconst duration = Math.floor(durationInSeconds * WEBCODECS_TIMESCALE);\n\n\tconst audioSample: MediaParserAudioSample = {\n\t\tdata,\n\t\tdecodingTimestamp: timestamp,\n\t\tduration,","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/mp3/seek/audio-sample-from-cbr.ts#L14-L50","documentation":"Thrown in getAudioSampleFromCbr() when state.mp3.getMp3Info() returns null at seek time. The CBR seek math needs the parsed MP3 info (layer, sampleRate, mpegVersion) that is normally populated after the first frame is parsed. A null means the parser has not yet established the MP3 stream info.","triggerScenarios":"Invoking a CBR seek before the media parser has finished reading the initial MP3 header(s) and populated mp3Info. Also possible if the seek target offset precedes the first valid frame or if the stream never produced a parseable MP3 frame.","commonSituations":"Seeking very early in a streaming/progressive load before enough bytes are available; feeding a non-MP3 stream into the MP3 code path; a parser state that was reset between parses.","solutions":["Ensure the parser has consumed enough of the stream to populate mp3Info (wait for the first frame to be parsed) before seeking.","Verify the input is genuinely an MP3 before using the MP3 seek path.","Re-encode to guarantee a clean first frame and standard CBR layout."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure mp3Info is populated before issuing a CBR seek.\nconst mp3Info = state.mp3.getMp3Info();\nif (!mp3Info) {\n  // wait for the parser to parse the first frame, or reject the seek\n  throw new Error('Cannot seek: parser has not yet established MP3 info');\n}","typeGuard":"function hasMp3Info<T>(info: T | null): info is T {\n  return info != null;\n}","tryCatchPattern":"try {\n  const sample = getAudioSampleFromCbr({...});\n} catch (err) {\n  if (err instanceof Error && err.message === 'No MP3 info') {\n    // defer the seek until more of the stream is parsed\n  } else throw err;\n}","preventionTips":["Do not seek before the parser has parsed at least the first MP3 frame.","Gate seek APIs on getMp3Info() returning non-null.","Confirm the input is actually MP3 before using the MP3 seek path."],"tags":["mp3","cbr","seek","media-parser"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}