google/ExoPlayer · critical · RuntimeException

Error instantiating MIDI extension

Error message

Error instantiating MIDI extension

What it means

DefaultRenderersFactory reflectively loads the built-in MIDI renderer (com.google.android.exoplayer2.decoder.midi.MidiRenderer, a no-arg constructor) as part of building audio renderers when extension renderer mode is enabled. If the class is present but cannot be constructed (any exception other than ClassNotFoundException), the factory throws a RuntimeException with the cause. Since MidiRenderer ships in the core artifact, hitting this almost always indicates a corrupted or mismatched build rather than a missing optional dependency.

Source

Thrown at library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java:488

    if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
      return;
    }
    int extensionRendererIndex = out.size();
    if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {
      extensionRendererIndex--;
    }

    try {
      Class<?> clazz = Class.forName("com.google.android.exoplayer2.decoder.midi.MidiRenderer");
      Constructor<?> constructor = clazz.getConstructor();
      Renderer renderer = (Renderer) constructor.newInstance();
      out.add(extensionRendererIndex++, renderer);
      Log.i(TAG, "Loaded MidiRenderer.");
    } catch (ClassNotFoundException e) {
      // Expected if the app was built without the extension.
    } catch (Exception e) {
      // The extension is present, but instantiation failed.
      throw new RuntimeException("Error instantiating MIDI extension", e);
    }

    try {
      // Full class names used for constructor args so the LINT rule triggers if any of them move.
      Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
      Constructor<?> constructor =
          clazz.getConstructor(
              android.os.Handler.class,
              com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
              com.google.android.exoplayer2.audio.AudioSink.class);
      Renderer renderer =
          (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);
      out.add(extensionRendererIndex++, renderer);
      Log.i(TAG, "Loaded LibopusAudioRenderer.");
    } catch (ClassNotFoundException e) {
      // Expected if the app was built without the extension.
    } catch (Exception e) {
      // The extension is present, but instantiation failed.

View on GitHub (pinned to dd430f7053)

Solutions

  1. Read the cause exception — it pinpoints whether the constructor was missing, inaccessible, or threw.
  2. Verify a single consistent com.google.android.exoplayer:exoplayer-core version across all modules (./gradlew dependencies).
  3. Keep the class and its constructor unobfuscated: -keep class com.google.android.exoplayer2.decoder.** { *; }.
  4. If MIDI playback is not needed, use EXTENSION_RENDERER_MODE_OFF, which skips this reflective block.

Example fix

// before
setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)

// after — proguard-rules.pro
//-keep class com.google.android.exoplayer2.decoder.midi.MidiRenderer { <init>(); }
Defensive patterns

Strategy: try-catch

Validate before calling

try {
  Class.forName("com.google.android.exoplayer2.decoder.midi.MidiRenderer").getConstructor();
} catch (ReflectiveOperationException e) {
  // do not enable extension renderer modes until fixed
}

Try / catch

try {
  player = new ExoPlayer.Builder(factoryWithExtensions).build(context);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().contains("MIDI extension")) {
    player = new ExoPlayer.Builder(new DefaultRenderersFactory(context)).build(context);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Building renderers with an extension renderer mode while the MidiRenderer class exists but its no-arg constructor is missing (obfuscated or different version) or its static/instance initializers throw.

Common situations: R8 full-mode rewriting or removing the no-arg constructor; a dependency resolution conflict pulling an older/newer core variant where part of the class is multidexed away; reflective instantiation blocked on newer runtimes.

Related errors


AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14). Data as JSON: /api/errors/66e9eb6d00bde22a. Report an issue: GitHub.