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

  1. Validate the full Opus header (mapping family, numStreams, numCoupled, stream map) against RFC 7845 before constructing the decoder.
  2. Ensure the bundled native libopus version matches the JNI wrapper and is loaded correctly.
  3. 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

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


AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14). Data as JSON: /api/errors/796958e99a568821. Report an issue: GitHub.