DrKLO/Telegram · error · OpusDecoderException
Invalid initialization data size
Error message
Invalid initialization data size
What it means
The OpusDecoder constructor requires the codec initializationData list to hold exactly 1 element (just the Opus identification header) or exactly 3 elements (header plus two 8-byte buffers for codec delay and seek pre-roll, the layout produced by ExoPlayer's Opus extractor). Any other size is treated as malformed codec private data and rejected before any header bytes are read.
Source
Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:93
public OpusDecoder(
int numInputBuffers,
int numOutputBuffers,
int initialInputBufferSize,
List<byte[]> initializationData,
@Nullable CryptoConfig cryptoConfig,
boolean outputFloat)
throws OpusDecoderException {
super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);
if (!OpusLibrary.isAvailable()) {
throw new OpusDecoderException("Failed to load decoder native libraries");
}
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);View on GitHub (pinned to 45ab8f4308)
Solutions
- Let ExoPlayer's built-in Opus extractor (Ogg/Opus or Matroska/Opus) populate initializationData rather than building the list by hand.
- Ensure initializationData is exactly Collections.singletonList(header) or [header, codecDelay(8 bytes), seekPreRoll(8 bytes)].
- Validate the source is a real Opus stream before routing it to LibopusAudioRenderer.
Example fix
// before List<byte[]> init = new ArrayList<>(); init.add(header); init.add(codecDelayShort); // wrong size -> forces 2-element list new OpusDecoder(..., init, ...); // after - either 1 header, or header + two 8-byte longs List<byte[]> init = Collections.singletonList(header); // or: Arrays.asList(header, longToBytes(codecDelayNs), longToBytes(seekPreRollNs)); new OpusDecoder(..., init, ...);
Defensive patterns
Strategy: validation
Validate before calling
List<byte[]> init = format.initializationData;
if (init == null || (init.size() != 1 && init.size() != 3)) {
throw new IllegalArgumentException(
"Opus initializationData must have 1 or 3 buffers, got " + (init == null ? 0 : init.size()));
}
new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, init, cryptoConfig, outputFloat); Try / catch
try {
new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);
} catch (OpusDecoderException e) {
if (e.getMessage().startsWith("Invalid initialization data size")) {
// mark format unsupported / re-extract
} else { throw e; }
} Prevention
- Always let the Opus extractor populate Format.initializationData.
- Never hand-build an Opus Format with arbitrary initializationData.
- In tests, use real Opus header bytes or fixtures copied from a real stream.
When it happens
Trigger: Constructing OpusDecoder with a Format whose initializationData was populated with the wrong number of buffers - a hand-built Format, a buggy custom extractor, or a file that is not genuinely Opus being fed to the Opus renderer.
Common situations: Unit tests that build a Format manually and forget the extra buffers; a demuxer that emits 2 or 4 buffers; media mislabeled as audio/opus; partial container corruption that makes the extractor emit no header buffer.
Related errors
- Invalid pre-skip or seek pre-roll
- Invalid header length
- 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/3f8313c1e4ac700a.
Report an issue: GitHub.