material-components/material-components-android · error · IllegalArgumentException

Invalid motion easing type: %s

Error message

Invalid motion easing type: %s

What it means

After confirming a legacy easing string starts with 'cubic-bezier(' or 'pathData:' style prefixes (isLegacyEasingAttribute), getLegacyThemeInterpolator tries both known types; if neither matches it throws IllegalArgumentException('Invalid motion easing type: ...'). This catches strings that look like legacy easings (e.g. end with ')') but use an unrecognized function name.

Source

Thrown at lib/java/com/google/android/material/motion/MotionUtils.java:154

      String controlPointsString = getLegacyEasingContent(easingString, EASING_TYPE_CUBIC_BEZIER);
      String[] controlPoints = controlPointsString.split(",");
      if (controlPoints.length != 4) {
        throw new IllegalArgumentException(
            "Motion easing theme attribute must have 4 control points if using bezier curve"
                + " format; instead got: "
                + controlPoints.length);
      }

      float controlX1 = getLegacyControlPoint(controlPoints, 0);
      float controlY1 = getLegacyControlPoint(controlPoints, 1);
      float controlX2 = getLegacyControlPoint(controlPoints, 2);
      float controlY2 = getLegacyControlPoint(controlPoints, 3);
      return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
    } else if (isLegacyEasingType(easingString, EASING_TYPE_PATH)) {
      String path = getLegacyEasingContent(easingString, EASING_TYPE_PATH);
      return new PathInterpolator(PathParser.createPathFromPathData(path));
    } else {
      throw new IllegalArgumentException("Invalid motion easing type: " + easingString);
    }
  }

  private static boolean isLegacyEasingAttribute(String easingString) {
    return isLegacyEasingType(easingString, EASING_TYPE_CUBIC_BEZIER)
        || isLegacyEasingType(easingString, EASING_TYPE_PATH);
  }

  private static boolean isLegacyEasingType(String easingString, String easingType) {
    return easingString.startsWith(easingType + EASING_TYPE_FORMAT_START)
        && easingString.endsWith(EASING_TYPE_FORMAT_END);
  }

  private static String getLegacyEasingContent(String easingString, String easingType) {
    return easingString.substring(
        easingType.length() + EASING_TYPE_FORMAT_START.length(),
        easingString.length() - EASING_TYPE_FORMAT_END.length());
  }

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Use only 'cubic-bezier(x1,y1,x2,y2)' or 'pathData:<android path string>' string formats
  2. Replace custom curves with an @interpolator resource and the *Interpolator attribute variant
  3. For standard curves, use built-in theme defaults rather than overriding with a string

Example fix

<!-- before -->
<item name="motionEasingStandard">easeInOut(0.4, 0, 0.2, 1)</item>
<!-- after -->
<item name="motionEasingStandard">cubic-bezier(0.4, 0, 0.2, 1)</item>
Defensive patterns

Strategy: validation

Validate before calling

fun isSupportedEasingString(s: String): Boolean =
    s.startsWith("cubic-bezier(") && s.endsWith(")") ||
    s.startsWith("pathData:")

Try / catch

catch (e: IllegalArgumentException) { Log.w(TAG, "Unsupported easing type; falling back", e); useDefaultInterpolator() }

Prevention

When it happens

Trigger: A theme string easing like 'ease-in-out(...)' or 'spring(1,2)' — starts with an unknown function and ends with ')' — resolved via resolveThemeInterpolator; the type check for cubic-bezier/pathData prefixes fails and the else branch throws.

Common situations: Porting CSS easing names (ease-in, ease-out) that Material does not support; typos like 'cubicBezier(...)' or 'path(...)'; expecting spring strings to work.

Related errors


AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14). Data as JSON: /api/errors/95ed00bf3e33e357. Report an issue: GitHub.