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

Motion easing control point value must be between 0 and 1; i

Error message

Motion easing control point value must be between 0 and 1; instead got: %s

What it means

When parsing control points from a legacy cubic-bezier easing string, getLegacyControlPoint requires each of the four floats to be within [0, 1]; a value outside that range throws IllegalArgumentException including the offending number. This matches PathInterpolator's own constraint on control points (x-axis especially), enforced earlier with a clearer message.

Source

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

    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());
  }

  private static float getLegacyControlPoint(String[] controlPoints, int index) {
    float controlPoint = Float.parseFloat(controlPoints[index]);
    if (controlPoint < 0 || controlPoint > 1) {
      throw new IllegalArgumentException(
          "Motion easing control point value must be between 0 and 1; instead got: "
              + controlPoint);
    }
    return controlPoint;
  }
}

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Clamp all four control point values to the [0, 1] range
  2. For overshoot/elastic curves, use an @interpolator resource built from a PathInterpolator XML (paths may still be constrained, so prefer overshoot interpolators)
  3. Use built-in material easing defaults for standard motion

Example fix

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

Strategy: validation

Validate before calling

fun clampControlPoints(points: FloatArray): FloatArray =
    FloatArray(points.size) { i -> points[i].coerceIn(0f, 1f) }

Try / catch

catch (e: IllegalArgumentException) { Log.w(TAG, "Control point out of range; clamping", e); useClampedCurve() }

Prevention

When it happens

Trigger: A theme string like 'cubic-bezier(1.2, 0, 0.2, 1)' or a negative control point resolved through resolveThemeInterpolator; Float.parseFloat succeeds but the range check fails.

Common situations: Copying CSS curves with y-values outside [0,1] (legal in CSS for overshoot, illegal here); negative values intended as anticipation; locale issues where a decimal comma breaks parsing into a different number.

Related errors


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