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

A MaterialSpring style must have a damping value.

Error message

A MaterialSpring style must have a damping value.

What it means

When resolving a MaterialSpring style into a SpringForce, MotionUtils requires a damping value in addition to stiffness. Float.MIN_VALUE is used as the sentinel default, and its presence means the style omitted MaterialSpring_damping, which throws IllegalArgumentException because SpringForce needs a damping ratio to behave predictably.

Source

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

      @NonNull Context context, @AttrRes int attrResId, @StyleRes int defStyleRes) {

    TypedValue tv = MaterialAttributes.resolve(context, attrResId);
    TypedArray a;
    if (tv == null) {
      a = context.obtainStyledAttributes(null, R.styleable.MaterialSpring, 0, defStyleRes);
    } else {
      a = context.obtainStyledAttributes(tv.resourceId, R.styleable.MaterialSpring);
    }

    SpringForce springForce = new SpringForce();
    try {
      float stiffness = a.getFloat(R.styleable.MaterialSpring_stiffness, Float.MIN_VALUE);
      if (stiffness == Float.MIN_VALUE) {
        throw new IllegalArgumentException("A MaterialSpring style must have stiffness value.");
      }
      float damping = a.getFloat(R.styleable.MaterialSpring_damping, Float.MIN_VALUE);
      if (damping == Float.MIN_VALUE) {
        throw new IllegalArgumentException("A MaterialSpring style must have a damping value.");
      }

      springForce.setStiffness(stiffness);
      springForce.setDampingRatio(damping);
    } finally {
      a.recycle();
    }
    return springForce;
  }

  /**
   * Resolve a duration from a material duration theme attribute.
   *
   * @param context the context from where the theme attribute will be resolved.
   * @param attrResId the {@code motionDuration*} theme attribute to resolve
   * @param defaultDuration the duration to be returned if unable to resolve {@code attrResId}
   * @return the resolved {@code int} duration which {@code attrResId} points to or the {@code
   *     defaultDuration} if resolution was unsuccessful.

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Add <item name="damping">[value between 0 and 1+]</item> to the spring style
  2. Parent the custom style to a material spring style so defaults are inherited
  3. Validate both items exist before resolving, using obtainStyledAttributes in debug builds

Example fix

<!-- before -->
<style name="MySpring">
  <item name="stiffness">400</item>
</style>
<!-- after -->
<style name="MySpring">
  <item name="stiffness">400</item>
  <item name="damping">0.75</item>
</style>
Defensive patterns

Strategy: validation

Validate before calling

// Assert the style declares both spring values in a unit test
@Test fun springStyleIsComplete() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val a = context.obtainStyledAttributes(R.style.MySpring, R.styleable.MaterialSpring)
    assertTrue(a.hasValue(R.styleable.MaterialSpring_stiffness))
    assertTrue(a.hasValue(R.styleable.MaterialSpring_damping))
    a.recycle()
}

Try / catch

catch (e: IllegalArgumentException) { Log.e(TAG, "Spring style missing damping", e); useDefaultSpringForce() }

Prevention

When it happens

Trigger: resolveAsSpringForce resolves a style that defines stiffness but omits damping; e.g. a custom style overriding a motionEasing/spring theme attribute with only <item name="stiffness">, or an incorrectly parented style missing the damping default.

Common situations: Copying a spring style from docs that only shows stiffness; upgrading Material library where damping defaults moved to a parent style the app no longer inherits; hand-writing the style in values/ without a correct parent.

Related errors


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