DrKLO/Telegram · error · OpusDecoderException
Failed to initialize decoder
Error message
Failed to initialize decoder
What it means
After all Java-side validation, opusInit (a native JNI call wrapping opus_multistream_decoder_init) must return a non-zero decoder context. A return value of 0 means the native libopus failed to initialize the multistream decoder. The Java checks passed but libopus itself rejected the parameters (numStreams/numCoupled/streamMap inconsistent with channelCount, an unsupported configuration, or a native/memory failure).
Source
Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:137
throw new OpusDecoderException("Invalid header, missing stream map");
}
numStreams = 1;
numCoupled = (channelCount == 2) ? 1 : 0;
streamMap[0] = 0;
streamMap[1] = 1;
} else {
if (headerBytes.length < 21 + channelCount) {
throw new OpusDecoderException("Invalid header length");
}
// Read the channel mapping.
numStreams = headerBytes[19] & 0xFF;
numCoupled = headerBytes[20] & 0xFF;
System.arraycopy(headerBytes, 21, streamMap, 0, channelCount);
}
nativeDecoderContext =
opusInit(SAMPLE_RATE, channelCount, numStreams, numCoupled, gain, streamMap);
if (nativeDecoderContext == 0) {
throw new OpusDecoderException("Failed to initialize decoder");
}
setInitialInputBufferSize(initialInputBufferSize);
this.outputFloat = outputFloat;
if (outputFloat) {
opusSetFloatOutput();
}
}
/**
* Sets whether discard padding is enabled. When enabled, discard padding samples (provided as
* supplemental data on the input buffer) will be removed from the end of the decoder output.
*
* <p>This method is experimental, and will be renamed or removed in a future release.
*/
public void experimentalSetDiscardPaddingEnabled(boolean enabled) {
this.experimentalDiscardPaddingEnabled = enabled;
}View on GitHub (pinned to 45ab8f4308)
Solutions
- Validate the full Opus header (mapping family, numStreams, numCoupled, stream map) against RFC 7845 before constructing the decoder.
- Ensure the bundled native libopus version matches the JNI wrapper and is loaded correctly.
- Provide a fallback audio renderer so playback degrades gracefully when Opus init fails.
Defensive patterns
Strategy: fallback
Try / catch
try {
decoder = new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);
} catch (OpusDecoderException e) {
if (e.getMessage().equals("Failed to initialize decoder")) {
// native init failed: fall back to the platform Opus decoder / another renderer
decoder = null;
} else { throw e; }
} Prevention
- Validate the full Opus header (mapping family, numStreams, numCoupled, stream map) against RFC 7845 upstream.
- Keep the native libopus build version in sync with the JNI wrapper.
- Register a fallback audio renderer so a native init failure degrades playback rather than aborting.
When it happens
Trigger: opusInit returns 0 - typically because numStreams and numCoupled are inconsistent with channelCount, the stream map is invalid, or the native library hit an allocation/version error.
Common situations: A header that passes the shallow Java validation but is internally inconsistent (e.g. a hand-crafted stream map); a native libopus build/version mismatch; low-memory conditions on the native heap.
Related errors
- Opus decoder does not support secure decode
- Invalid initialization data size
- Invalid pre-skip or seek pre-roll
- Invalid header length
- Invalid channel count: {channelCount}
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/796958e99a568821.
Report an issue: GitHub.