google/ExoPlayer · error · RuntimeException

Failed to load MediaPipeShaderProgram

Error message

Failed to load MediaPipeShaderProgram

What it means

RuntimeException thrown by the MediaPipe effects factory lambda in TransformerActivity when Constructor.newInstance fails, i.e. the MediaPipeShaderProgram class could not be constructed. The reflection-based construction fails when the MediaPipe artifacts are absent from the runtime classpath or the constructor signature does not match. The demo already shows a toast and the outer try/catch downgrades selection, so this crash only escapes if the factory is invoked later during composition building.

Source

Thrown at demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java:467

                String.class,
                boolean.class,
                String.class,
                String.class);
        effects.add(
            (GlEffect)
                (Context context, boolean useHdr) -> {
                  try {
                    return (GlShaderProgram)
                        constructor.newInstance(
                            context,
                            useHdr,
                            /* graphName= */ "edge_detector_mediapipe_graph.binarypb",
                            /* isSingleFrameGraph= */ true,
                            /* inputStreamName= */ "input_video",
                            /* outputStreamName= */ "output_video");
                  } catch (Exception e) {
                    runOnUiThread(() -> showToast(R.string.no_media_pipe_error));
                    throw new RuntimeException("Failed to load MediaPipeShaderProgram", e);
                  }
                });
      } catch (Exception e) {
        showToast(R.string.no_media_pipe_error);
      }
    }
    if (selectedEffects[ConfigurationActivity.COLOR_FILTERS_INDEX]) {
      switch (bundle.getInt(ConfigurationActivity.COLOR_FILTER_SELECTION)) {
        case ConfigurationActivity.COLOR_FILTER_GRAYSCALE:
          effects.add(RgbFilter.createGrayscaleFilter());
          break;
        case ConfigurationActivity.COLOR_FILTER_INVERTED:
          effects.add(RgbFilter.createInvertedFilter());
          break;
        case ConfigurationActivity.COLOR_FILTER_SEPIA:
          // W3C Sepia RGBA matrix with sRGB as a target color space:
          // https://www.w3.org/TR/filter-effects-1/#sepiaEquivalent
          // The matrix is defined for the sRGB color space and the Transformer library

View on GitHub (pinned to dd430f7053)

Solutions

  1. Add the required MediaPipe dependencies (com.google.mediapipe:mediapipe-* and the extension artifacts) to the demo's gradle config
  2. Verify the MediaPipeShaderProgram constructor signature matches the invoked (context, useHdr, graphName, isSingleFrameGraph, inputStreamName, outputStreamName) parameter list for your version
  3. Bundle the 'edge_detector_mediapipe_graph.binarypb' asset (and any .task/.binarypb files) with the APK
  4. Add proguard keep rules for com.google.android.exoplayer2.effect and com.google.mediapipe classes when minifying

Example fix

// before
} catch (Exception e) {
  runOnUiThread(() -> showToast(R.string.no_media_pipe_error));
  throw new RuntimeException("Failed to load MediaPipeShaderProgram", e);
}

// after: resolve the constructor once, before adding the effect, and skip the effect gracefully
try {
  constructor = mediaPipeShaderProgramClass.getConstructor(
      Context.class, boolean.class, String.class, boolean.class, String.class, String.class);
} catch (NoSuchMethodException e) {
  showToast(R.string.no_media_pipe_error); // effect unavailable; do not add it
}
Defensive patterns

Strategy: validation

Validate before calling

private boolean mediaPipeEffectAvailable() {
  try {
    Class<?> clazz = Class.forName("com.google.mediapipe.framework.MediaPipeShaderProgram");
    clazz.getConstructor(Context.class, boolean.class,
        String.class, boolean.class, String.class, String.class);
    return true; // constructor resolvable -> deps present and signature matches
  } catch (ReflectiveOperationException e) {
    return false;
  }
}

Try / catch

if (!mediaPipeEffectAvailable()) {
  showToast(R.string.no_media_pipe_error); // skip the effect, keep export usable
} else {
  effects.add((GlEffect) (context, useHdr) -> {
    try {
      return (GlShaderProgram) constructor.newInstance(context, useHdr,
          "edge_detector_mediapipe_graph.binarypb", true, "input_video", "output_video");
    } catch (Exception e) {
      throw new RuntimeException("Failed to load MediaPipeShaderProgram", e);
    }
  });
}

Prevention

When it happens

Trigger: Selecting the MediaPipe effect in the Transformer demo without the MediaPipe shader/dependencies on the classpath; version mismatch where MediaPipeShaderProgram's constructor args (graphName, isSingleFrameGraph, inputStreamName, outputStreamName) differ from those passed; graph asset 'edge_detector_mediapipe_graph.binarypb' missing from assets.

Common situations: Building the demo from source without the optional MediaPipe AARs; upgrading Media3/MediaPipe versions that changed the constructor; proguard stripping the reflected class in release builds.

Related errors


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