material-components/material-components-android · error · IllegalStateException
Couldn't set RippleDrawable radius
Error message
Couldn't set RippleDrawable radius
What it means
On API levels below 23, RippleDrawable.setRadius() does not exist, so DrawableUtils.setRippleDrawableRadius falls back to reflection, invoking the hidden setMaxRadius(int) method. If that hidden method is missing (OEM framework changes) or inaccessible — most commonly because ProGuard/R8 obfuscated or stripped it, or the method was renamed in a vendor fork — the reflective call fails and the IllegalStateException wraps the underlying NoSuchMethodException / IllegalAccessException / InvocationTargetException.
Source
Thrown at lib/java/com/google/android/material/drawable/DrawableUtils.java:162
} catch (XmlPullParserException | IOException e) {
NotFoundException exception =
new NotFoundException("Can't load badge resource ID #0x" + Integer.toHexString(id));
exception.initCause(e);
throw exception;
}
}
public static void setRippleDrawableRadius(@Nullable RippleDrawable drawable, int radius) {
if (VERSION.SDK_INT >= VERSION_CODES.M) {
drawable.setRadius(radius);
} else {
try {
@SuppressLint("PrivateApi")
Method setMaxRadiusMethod =
RippleDrawable.class.getDeclaredMethod("setMaxRadius", int.class);
setMaxRadiusMethod.invoke(drawable, radius);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException("Couldn't set RippleDrawable radius", e);
}
}
}
/**
* Wraps and mutates the passed in drawable so that it may be used for tinting if a tintList is
* present. Also applies the tintMode if present.
*/
@Nullable
public static Drawable createTintableDrawableIfNeeded(
@Nullable Drawable drawable, @Nullable ColorStateList tintList, @Nullable Mode tintMode) {
return createTintableMutatedDrawableIfNeeded(
drawable, tintList, tintMode, /* forceMutate= */ false);
}
/**
* Wraps and mutates the passed in drawable so that it may be used for tinting if a tintList is
* present. Also applies the tintMode if present. If there's not a tintList and the API level is <View on GitHub (pinned to ac7e18efee)
Solutions
- Add ProGuard keep rules so reflection survives minification: -keepclassmembers class android.graphics.drawable.RippleDrawable { void setMaxRadius(int); }
- Raise minSdk to 23+ so the public setRadius() path is used and reflection is avoided entirely.
- Guard the call: only invoke setRippleDrawableRadius when Build.VERSION.SDK_INT >= 23, skipping custom radius on older devices.
Example fix
// before
DrawableUtils.setRippleDrawableRadius(ripple, radiusPx); // crashes when minified on API<23
// after
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
DrawableUtils.setRippleDrawableRadius(ripple, radiusPx);
}
// proguard-rules.pro
// -keepclassmembers class android.graphics.drawable.RippleDrawable { void setMaxRadius(int); } Defensive patterns
Strategy: try-catch
Validate before calling
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
DrawableUtils.setRippleDrawableRadius(drawable, radius);
} // else: skip custom radius on pre-M Try / catch
try {
DrawableUtils.setRippleDrawableRadius(drawable, radius);
} catch (IllegalStateException e) {
// reflection failed on pre-M; fall back to default ripple radius, do not crash UI
Log.w(TAG, "Custom ripple radius unsupported on this device", e);
} Prevention
- Keep -keepclassmembers rules for RippleDrawable.setMaxRadius in proguard-rules.pro.
- Test minified release builds on (or emulated) API < 23 devices.
- Consider raising minSdkVersion to 23 to remove the reflection path entirely.
When it happens
Trigger: Running on an API < 23 device with a minified release build where RippleDrawable.setMaxRadius is removed by ProGuard/R8; OEM-modified framework classes without the hidden method; calling setRippleDrawableRadius directly (e.g. when sizing FAB ripples) on pre-M devices.
Common situations: Works in debug, crashes only in minified release on old devices; shipping an app with minSdk < 23 that customizes ripple radius via Material components (e.g. FloatingActionButton ripple sizing).
Related errors
- secondaryIconGravity cannot have the same alignment as iconG
- Attempted to set ShapeAppearanceModel on a MaterialButton wh
- Attempted to get ShapeAppearanceModel from a MaterialButton
- Attempted to set ShapeAppearance on a MaterialButton which h
- Attempted to get ShapeAppearance from a MaterialButton which
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/bc9277706cdc835f.
Report an issue: GitHub.