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);
}
@OverrideView on GitHub (pinned to ac7e18efee)
Solutions
- Replace every non-ObjectAnimator child with an ObjectAnimator (use ObjectAnimator.ofFloat/ofInt with a target and property name, or PropertyValuesHolder).
- If animating a raw value with no target property, wrap the logic in a custom Property implementation and use ObjectAnimator with it.
- 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
- Build animator sets exclusively from ObjectAnimator when they feed MotionSpec.
- Prefer MotionSpec.createFromResource(context, animResId) with verified <objectAnimator> XML.
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
- Email %d does not exist.
- Color names need to be at least four and correspond to attri
- Album %d does not exist.
- AppBarLayout is always vertical and does not support horizon
- customBadgeParent must be a FrameLayout
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/1ad9a2a981f07af2.
Report an issue: GitHub.