material-components/material-components-android · error · IllegalArgumentException
Motion easing theme attribute must be an @interpolator resou
Error message
Motion easing theme attribute must be an @interpolator resource for ?attr/motionEasing*Interpolator attributes or a string for ?attr/motionEasing* attributes.
What it means
resolveThemeInterpolator accepts ?attr/motionEasing* theme attributes in two shapes: a string (legacy programmatic easing format like cubic-bezier(...) or pathData) or an @interpolator resource for the *Interpolator variants. If the resolved TypedValue type is anything other than TYPE_STRING, the attribute is neither of those shapes and the method throws IllegalArgumentException.
Source
Thrown at lib/java/com/google/android/material/motion/MotionUtils.java:120
* @param context context from where the theme attribute will be resolved
* @param attrResId the {@code motionEasing*} theme attribute to resolve
* @param defaultInterpolator the interpolator to be returned if unable to resolve {@code
* attrResId}.
* @return the resolved {@link TimeInterpolator} which {@code attrResId} points to or the {@code
* defaultInterpolator} if resolution was unsuccessful.
*/
@NonNull
public static TimeInterpolator resolveThemeInterpolator(
@NonNull Context context,
@AttrRes int attrResId,
@NonNull TimeInterpolator defaultInterpolator) {
TypedValue easingValue = new TypedValue();
if (!context.getTheme().resolveAttribute(attrResId, easingValue, true)) {
return defaultInterpolator;
}
if (easingValue.type != TypedValue.TYPE_STRING) {
throw new IllegalArgumentException(
"Motion easing theme attribute must be an @interpolator resource for"
+ " ?attr/motionEasing*Interpolator attributes or a string for"
+ " ?attr/motionEasing* attributes.");
}
String easingString = String.valueOf(easingValue.string);
if (isLegacyEasingAttribute(easingString)) {
return getLegacyThemeInterpolator(easingString);
}
return AnimationUtils.loadInterpolator(context, easingValue.resourceId);
}
private static TimeInterpolator getLegacyThemeInterpolator(String easingString) {
if (isLegacyEasingType(easingString, EASING_TYPE_CUBIC_BEZIER)) {
String controlPointsString = getLegacyEasingContent(easingString, EASING_TYPE_CUBIC_BEZIER);
String[] controlPoints = controlPointsString.split(",");
if (controlPoints.length != 4) {View on GitHub (pinned to ac7e18efee)
Solutions
- Point the ?attr/motionEasing* attribute at an @interpolator resource (for *Interpolator variants)
- Or use a string value in a recognized format: 'cubic-bezier(x1,y1,x2,y2)' or 'pathData:...'
- Double-check the attribute name variant matches the value type being set
Example fix
<!-- before --> <style name="Theme.MyApp" parent="Theme.Material3.DayNight"> <item name="motionEasingStandardInterpolator">@integer/my_easing</item> </style> <!-- after --> <style name="Theme.MyApp" parent="Theme.Material3.DayNight"> <item name="motionEasingStandardInterpolator">@interpolator/mtrl_fast_out_slow_in</item> </style>
Defensive patterns
Strategy: validation
Validate before calling
// Verify the theme attribute resolves to a string or interpolator before use
fun safeResolveInterpolator(context: Context, attr: Int, default: TimeInterpolator): TimeInterpolator {
val tv = TypedValue()
if (!context.theme.resolveAttribute(attr, tv, true)) return default
return if (tv.type == TypedValue.TYPE_STRING) {
try { MotionUtils.resolveThemeInterpolator(context, attr, default) } catch (e: Exception) { default }
} else default
} Try / catch
catch (e: IllegalArgumentException) { Log.w(TAG, "Bad motionEasing attribute; falling back to default interpolator", e); useDefaultInterpolator() } Prevention
- Use *Interpolator attribute variants only with @interpolator resources
- Use plain motionEasing* attributes only with string easing formats
- Prefer built-in material theme defaults unless a custom curve is truly needed
When it happens
Trigger: Setting a ?attr/motionEasing* attribute to a non-string, non-interpolator resource type — e.g. a color, dimension, integer, or boolean — in a theme; resolveThemeInterpolator then reads easingValue.type != TYPE_STRING and throws.
Common situations: Copy-pasting theme overrides and assigning a reference to a non-interpolator resource; confusing motionEasingLinear (string format) with motionEasingLinearInterpolator (@interpolator); migration from string easings to interpolator resources with the wrong target.
Related errors
- Invalid motion easing type: %s
- Keylines being linearly interpolated must have the same item
- Keylines being linearly interpolated must have the same numb
- Caller must set a non-null RevealInfo before calling this.
- A MaterialSpring style must have stiffness value.
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/951451348c0e5e65.
Report an issue: GitHub.