{"record":{"id":"66e9eb6d00bde22a","repo":"google/ExoPlayer","slug":"error-instantiating-midi-extension","errorCode":null,"errorMessage":"Error instantiating MIDI extension","messagePattern":"Error instantiating MIDI extension","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java","lineNumber":488,"sourceCode":"    if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {\n      return;\n    }\n    int extensionRendererIndex = out.size();\n    if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) {\n      extensionRendererIndex--;\n    }\n\n    try {\n      Class<?> clazz = Class.forName(\"com.google.android.exoplayer2.decoder.midi.MidiRenderer\");\n      Constructor<?> constructor = clazz.getConstructor();\n      Renderer renderer = (Renderer) constructor.newInstance();\n      out.add(extensionRendererIndex++, renderer);\n      Log.i(TAG, \"Loaded MidiRenderer.\");\n    } catch (ClassNotFoundException e) {\n      // Expected if the app was built without the extension.\n    } catch (Exception e) {\n      // The extension is present, but instantiation failed.\n      throw new RuntimeException(\"Error instantiating MIDI extension\", e);\n    }\n\n    try {\n      // Full class names used for constructor args so the LINT rule triggers if any of them move.\n      Class<?> clazz = Class.forName(\"com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer\");\n      Constructor<?> constructor =\n          clazz.getConstructor(\n              android.os.Handler.class,\n              com.google.android.exoplayer2.audio.AudioRendererEventListener.class,\n              com.google.android.exoplayer2.audio.AudioSink.class);\n      Renderer renderer =\n          (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);\n      out.add(extensionRendererIndex++, renderer);\n      Log.i(TAG, \"Loaded LibopusAudioRenderer.\");\n    } catch (ClassNotFoundException e) {\n      // Expected if the app was built without the extension.\n    } catch (Exception e) {\n      // The extension is present, but instantiation failed.","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java#L470-L506","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the cause exception — it pinpoints whether the constructor was missing, inaccessible, or threw.","Verify a single consistent com.google.android.exoplayer:exoplayer-core version across all modules (./gradlew dependencies).","Keep the class and its constructor unobfuscated: -keep class com.google.android.exoplayer2.decoder.** { *; }.","If MIDI playback is not needed, use EXTENSION_RENDERER_MODE_OFF, which skips this reflective block."],"exampleFix":"// before\nsetExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)\n\n// after — proguard-rules.pro\n//-keep class com.google.android.exoplayer2.decoder.midi.MidiRenderer { <init>(); }","handlingStrategy":"try-catch","validationCode":"try {\n  Class.forName(\"com.google.android.exoplayer2.decoder.midi.MidiRenderer\").getConstructor();\n} catch (ReflectiveOperationException e) {\n  // do not enable extension renderer modes until fixed\n}","typeGuard":null,"tryCatchPattern":"try {\n  player = new ExoPlayer.Builder(factoryWithExtensions).build(context);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"MIDI extension\")) {\n    player = new ExoPlayer.Builder(new DefaultRenderersFactory(context)).build(context);\n  } else { throw e; }\n}","preventionTips":["Run ./gradlew dependencies and confirm a single exoplayer-core version","Keep com.google.android.exoplayer2.decoder.** intact under R8","Smoke-test player construction in CI on a minSdk emulator"],"tags":["exoplayer","reflection","midi","renderer","proguard","initialization"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}