DrKLO/Telegram · error · OpusDecoderException
Invalid header length
Error message
Invalid header length
What it means
The Opus identification header (initializationData.get(0)) must be at least 19 bytes: RFC 7845 defines the fixed header fields (magic, version, channels, pre-skip, sample rate, gain, channel mapping family) ending at byte index 18. If headerBytes.length < 19 the header is truncated and the decoder refuses to parse channel/gain/mapping fields that follow.
Source
Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:105
this.cryptoConfig = cryptoConfig;
if (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
throw new OpusDecoderException("Opus decoder does not support secure decode");
}
int initializationDataSize = initializationData.size();
if (initializationDataSize != 1 && initializationDataSize != 3) {
throw new OpusDecoderException("Invalid initialization data size");
}
if (initializationDataSize == 3
&& (initializationData.get(1).length != 8 || initializationData.get(2).length != 8)) {
throw new OpusDecoderException("Invalid pre-skip or seek pre-roll");
}
preSkipSamples = getPreSkipSamples(initializationData);
seekPreRollSamples = getSeekPreRollSamples(initializationData);
skipSamples = preSkipSamples;
byte[] headerBytes = initializationData.get(0);
if (headerBytes.length < 19) {
throw new OpusDecoderException("Invalid header length");
}
channelCount = getChannelCount(headerBytes);
if (channelCount > 8) {
throw new OpusDecoderException("Invalid channel count: " + channelCount);
}
int gain = readSignedLittleEndian16(headerBytes, 16);
byte[] streamMap = new byte[8];
int numStreams;
int numCoupled;
if (headerBytes[18] == 0) { // Channel mapping
// If there is no channel mapping, use the defaults.
if (channelCount > 2) { // Maximum channel count with default layout.
throw new OpusDecoderException("Invalid header, missing stream map");
}
numStreams = 1;
numCoupled = (channelCount == 2) ? 1 : 0;
streamMap[0] = 0;View on GitHub (pinned to 45ab8f4308)
Solutions
- Re-extract the stream from a known-good Opus source so the full identification header is delivered.
- Validate headerBytes.length >= 19 before constructing the decoder and reject the Format early with a clearer error.
Example fix
// before
byte[] header = format.initializationData.get(0); // possibly < 19 bytes
new OpusDecoder(..., format.initializationData, ...);
// after
byte[] header = format.initializationData.get(0);
if (header.length < 19) {
throw new OpusDecoderException("Truncated Opus header: " + header.length);
}
new OpusDecoder(..., format.initializationData, ...); Defensive patterns
Strategy: validation
Validate before calling
byte[] header = format.initializationData.get(0);
if (header == null || header.length < 19) {
throw new IllegalArgumentException("Opus identification header must be >= 19 bytes");
}
new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, format.initializationData, cryptoConfig, outputFloat); Try / catch
try {
new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);
} catch (OpusDecoderException e) {
if (e.getMessage().equals("Invalid header length")) {
// header truncated: reject format / re-extract
} else { throw e; }
} Prevention
- Reject Opus formats whose header is shorter than 19 bytes before decoding.
- Re-extract from a known-good source when the header looks truncated.
When it happens
Trigger: A truncated or corrupted Opus identification header extracted from a damaged Ogg/Opus or Matroska file, or a header buffer that was clipped during demuxing.
Common situations: Damaged downloads, partial files, a demuxer bug that returns a short buffer, or test content with a stub header.
Related errors
- Invalid initialization data size
- Invalid pre-skip or seek pre-roll
- Invalid channel count: {channelCount}
- Invalid header, missing stream map
- Opus decoder does not support secure decode
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/9600a03188047bce.
Report an issue: GitHub.