{"record":{"id":"05b39eadb083942c","repo":"remotion-dev/remotion","slug":"invalid-aac-codec-private-length","errorCode":null,"errorMessage":"Invalid AAC codec private length","messagePattern":"Invalid AAC codec private length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/aac-codecprivate.ts","lineNumber":144,"sourceCode":"\n\tconst bits = `${audioObjectType.toString(2).padStart(5, '0')}${getConfigForSampleRate(sampleRate).toString(2).padStart(4, '0')}${channelConfiguration.toString(2).padStart(4, '0')}000`;\n\tif (bits.length !== 16) {\n\t\tthrow new Error('Invalid AAC codec private ' + bits.length);\n\t}\n\n\tif (channelConfiguration === 0 || channelConfiguration > 7) {\n\t\tthrow new Error('Invalid channel configuration ' + channelConfiguration);\n\t}\n\n\tconst firstByte = parseInt(bits.slice(0, 8), 2);\n\tconst secondByte = parseInt(bits.slice(8, 16), 2);\n\n\treturn new Uint8Array([firstByte, secondByte]);\n};\n\nexport const parseAacCodecPrivate = (bytes: Uint8Array) => {\n\tif (bytes.length < 2) {\n\t\tthrow new Error('Invalid AAC codec private length');\n\t}\n\n\tconst bits = [...bytes].map((b) => b.toString(2).padStart(8, '0')).join('');\n\n\tlet offset = 0;\n\tconst audioObjectType = parseInt(bits.slice(offset, offset + 5), 2);\n\toffset += 5;\n\n\tconst samplingFrequencyIndex = parseInt(bits.slice(offset, offset + 4), 2);\n\toffset += 4;\n\n\tif (samplingFrequencyIndex === 0xf) {\n\t\toffset += 24;\n\t}\n\n\tconst channelConfiguration = parseInt(bits.slice(offset, offset + 4), 2);\n\toffset += 4;\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/aac-codecprivate.ts#L126-L162","documentation":"Thrown by parseAacCodecPrivate() when the supplied AAC codec-private byte array has fewer than 2 bytes. The parser needs at least 2 bytes (16 bits) to decode the audioObjectType (5 bits), samplingFrequencyIndex (4 bits), and channelConfiguration (4 bits) fields that form the minimal AAC AudioSpecificConfig. Any codec private data shorter than this is structurally invalid and cannot represent a real AAC stream.","triggerScenarios":"Calling parseAacCodecPrivate() (or parseMedia on a file whose track carries AAC codec data) where the codec-private bytes array has length 0 or 1. This happens when an MP4/Matroska/WebM container stores an empty or truncated CodecPrivate element for an AAC audio track, or when an internal caller passes a zero-length Uint8Array.","commonSituations":"Corrupt or partially downloaded media files where the AAC track's esds/CodecPrivate box is truncated. Hand-crafted or test fixtures with missing codec data. Files produced by buggy muxers that write a placeholder empty CodecPrivate for AAC tracks. Files misidentified as AAC that are actually another codec.","solutions":["Validate the media file integrity by re-muxing it with ffmpeg: `ffmpeg -i input.mp4 -c copy output.mp4` to repair the codec private data.","If you control the caller, guard with `if (bytes.length >= 2) { parseAacCodecPrivate(bytes); }` before invoking the parser.","Switch from the deprecated @remotion/media-parser to Mediabunny (https://www.remotion.dev/docs/mediabunny/metadata) which may handle the malformed input more gracefully.","Report the file as a bug to the Remotion team with the reproducer if the file plays correctly in standard players like VLC or ffprobe."],"exampleFix":"// before\nimport {parseAacCodecPrivate} from '@remotion/media-parser';\nconst info = parseAacCodecPrivate(track.codecPrivate); // throws if < 2 bytes\n\n// after\nimport {parseAacCodecPrivate} from '@remotion/media-parser';\nif (track.codecPrivate && track.codecPrivate.length >= 2) {\n  const info = parseAacCodecPrivate(track.codecPrivate);\n} else {\n  throw new Error(`Track has invalid AAC codec private: ${track.codecPrivate?.length ?? 0} bytes`);\n}","handlingStrategy":"validation","validationCode":"// Validate codec private length before parsing\nfunction hasValidAacCodecPrivate(bytes: Uint8Array | null | undefined): bytes is Uint8Array {\n  return bytes instanceof Uint8Array && bytes.length >= 2;\n}\n\n// Usage:\nif (hasValidAacCodecPrivate(track.codecPrivate)) {\n  const info = parseAacCodecPrivate(track.codecPrivate);\n} else {\n  console.warn('Skipping track: AAC codec private too short');\n}","typeGuard":"function isParseableAacCodecPrivate(bytes: unknown): bytes is Uint8Array {\n  return bytes instanceof Uint8Array && bytes.length >= 2;\n}","tryCatchPattern":"try {\n  const info = parseAacCodecPrivate(bytes);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid AAC codec private length') {\n    // Handle truncated codec private data\n    console.warn('AAC codec private data is too short, skipping track');\n  } else {\n    throw e;\n  }\n}","preventionTips":["Validate media file integrity with ffprobe before passing to parseMedia.","Ensure files are fully downloaded and not truncated before parsing.","Re-mux suspicious files with ffmpeg -c copy to normalize container structure.","Migrate from the deprecated @remotion/media-parser to Mediabunny."],"tags":["aac","media-parser","codec-private","validation"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}