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

Animator must be an ObjectAnimator:

Error message

Animator must be an ObjectAnimator: 

What it means

MotionSpec.createFromAnimatorSpec(AnimatorSet) (and related inflate paths) extracts per-property timing information from each child Animator via addInfoFromAnimator. Only ObjectAnimator carries a property name and PropertyValuesHolder data that MotionSpec can record, so any other Animator subtype (e.g. plain ValueAnimator or AnimatorSet) is rejected with IllegalArgumentException.

Source

Thrown at lib/java/com/google/android/material/animation/MotionSpec.java:220

    }
  }

  @NonNull
  private static MotionSpec createSpecFromAnimators(@NonNull List<Animator> animators) {
    MotionSpec spec = new MotionSpec();
    for (int i = 0, count = animators.size(); i < count; i++) {
      addInfoFromAnimator(spec, animators.get(i));
    }
    return spec;
  }

  private static void addInfoFromAnimator(@NonNull MotionSpec spec, Animator animator) {
    if (animator instanceof ObjectAnimator) {
      ObjectAnimator anim = (ObjectAnimator) animator;
      spec.setPropertyValues(anim.getPropertyName(), anim.getValues());
      spec.setTiming(anim.getPropertyName(), MotionTiming.createFromAnimator(anim));
    } else {
      throw new IllegalArgumentException("Animator must be an ObjectAnimator: " + animator);
    }
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof MotionSpec)) {
      return false;
    }

    MotionSpec that = (MotionSpec) o;

    return timings.equals(that.timings);
  }

  @Override

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Replace every non-ObjectAnimator child with an ObjectAnimator (use ObjectAnimator.ofFloat/ofInt with a target and property name, or PropertyValuesHolder).
  2. If animating a raw value with no target property, wrap the logic in a custom Property implementation and use ObjectAnimator with it.
  3. Check XML animator resources use <objectAnimator> elements, not <animator>.

Example fix

// before
AnimatorSet set = new AnimatorSet();
set.playTogether(ValueAnimator.ofFloat(0f, 1f)); // throws
MotionSpec spec = MotionSpec.createFromAnimatorSpec(set);

// after
ObjectAnimator fade = ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f);
AnimatorSet set = new AnimatorSet();
set.playTogether(fade);
MotionSpec spec = MotionSpec.createFromAnimatorSpec(set);
Defensive patterns

Strategy: type-guard

Type guard

private static boolean allChildrenAreObjectAnimators(AnimatorSet set) {
  for (Animator child : set.getChildAnimations()) {
    if (!(child instanceof ObjectAnimator)) return false;
  }
  return true;
}

Prevention

When it happens

Trigger: Calling MotionSpec.createFromAnimatorSpec with an AnimatorSet containing a ValueAnimator, TimeAnimator, or nested AnimatorSet instead of ObjectAnimator children; building an AnimatorSet in code where one child was created with ValueAnimator.ofInt/ofFloat.

Common situations: Hand-building an AnimatorSet to drive a Material component motion (e.g. MaterialCarousel or dismissible item animations) and mixing in a ValueAnimator for a non-property animation; converting an XML animator resource whose child is a <animator> (ValueAnimator) rather than <objectAnimator>.

Related errors


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