material-components/material-components-android · error · IllegalArgumentException
Keylines being linearly interpolated must have the same item
Error message
Keylines being linearly interpolated must have the same item size.
What it means
KeylineState.lerp (KeylineState.java:187) interpolates between two carousel keyline states position-by-position; a shared item size is a precondition because masked sizes are lerped per keyline and the resulting state must remain internally consistent. If from.getItemSize() != to.getItemSize() it throws IllegalArgumentException. This runs during carousel transitions such as strategy changes or configuration-driven keyline refreshes, so the two states being blended must come from the same layout parameters.
Source
Thrown at lib/java/com/google/android/material/carousel/KeylineState.java:187
return keylines.size() - anchorKeylines;
}
/** Returns the size of the carousel used to build this keyline state. */
int getCarouselSize() {
return carouselSize;
}
/**
* Linearly interpolate between two {@link KeylineState}s.
*
* @param from the start keyline state
* @param to the end keyline state
* @param progress the interpolation between from and to. When progress is 0, from will be
* returned. When progress is 1, to will be returned.
*/
static KeylineState lerp(KeylineState from, KeylineState to, float progress) {
if (from.getItemSize() != to.getItemSize()) {
throw new IllegalArgumentException(
"Keylines being linearly interpolated must have the same item size.");
}
List<Keyline> fromKeylines = from.getKeylines();
List<Keyline> toKeylines = to.getKeylines();
if (fromKeylines.size() != toKeylines.size()) {
throw new IllegalArgumentException(
"Keylines being linearly interpolated must have the same number of keylines.");
}
List<Keyline> keylines = new ArrayList<>();
for (int i = 0; i < from.getKeylines().size(); i++) {
keylines.add(Keyline.lerp(fromKeylines.get(i), toKeylines.get(i), progress));
}
int focalKeylineFirstIndex =
AnimationUtils.lerp(
from.getFirstFocalKeylineIndex(), to.getFirstFocalKeylineIndex(), progress);
int focalKeylineLastIndex =View on GitHub (pinned to ac7e18efee)
Solutions
- In custom CarouselStrategy subclasses, always rebuild KeylineStates from the current Carousel object in onChild initView — never cache and return states across size changes.
- Confirm both states passed to lerp derive from the same itemSize calculation; log from.getItemSize()/to.getItemSize() in a debug build to find the stale producer.
- Update to the latest patch release if the mismatch originates from library-internal state refresh bugs rather than your strategy.
Example fix
// before (custom strategy)
private KeylineState cached;
@Override
protected KeylineState onCalculate(Carousel carousel) {
if (cached != null) return cached; // stale after resize -> lerp mismatch
...
}
// after
@Override
protected KeylineState onCalculate(Carousel carousel) {
return create(self, carousel, /* item size from current carousel */ carousel.getCarouselLayoutManager() ...);
} Defensive patterns
Strategy: validation
Validate before calling
if (from.getItemSize() == to.getItemSize()) {
KeylineState.lerp(from, to, progress);
} else {
to = rebuildStateWithItemSize(to, from.getItemSize());
} Try / catch
try { KeylineState.lerp(from, to, progress); } catch (IllegalArgumentException e) { Log.w(TAG, "item size mismatch; jumping to target state"); return to; } Prevention
- Never cache KeylineStates across container size changes in custom strategies.
- Derive item size from the live Carousel on every onCalculate.
- Log from/to item sizes in debug builds to catch stale-state producers early.
When it happens
Trigger: Blending two KeylineStates built with different carousel item sizes — e.g. one from a CarouselStrategy configured for a small item size and another from a different strategy or a rebuilt state after container size/spacing changed mid-transition. Typically reached via library-internal animation code (KeylineStateList / CarouselLayoutManager) rather than direct app calls, since lerp is package-visible.
Common situations: Custom CarouselStrategy implementations that cache KeylineStates and return stale states built against an old item size after the RecyclerView's dimensions or itemSpacing changed (rotation, foldable posture change, window resize). Because the throw happens inside an animation frame, the crash surfaces far from the code that produced the mismatched states.
Related errors
- Keylines being linearly interpolated must have the same numb
- Anchor keylines cannot be focal.
- Anchor keylines must be either the first or last keyline.
- Keylines marked as focal must be placed next to each other.
- Keylines that are marked as focal must all have the same mas
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/027c28557f963aab.
Report an issue: GitHub.