material-components/material-components-android · error · IllegalArgumentException
Anchor keylines must be either the first or last keyline.
Error message
Anchor keylines must be either the first or last keyline.
What it means
KeylineState.Builder tracks latestAnchorKeylineIndex; anchors are legal only at the boundaries of the keyline list, so when a new anchor is added while a previous anchor exists and is not at index 0, the builder throws IllegalArgumentException (KeylineState.java:388). In practice this rejects a third anchor or an anchor placed after keylines that already follow a first anchor — the valid pattern is exactly one anchor at the very start and optionally one at the very end.
Source
Thrown at lib/java/com/google/android/material/carousel/KeylineState.java:388
@CanIgnoreReturnValue
public Builder addKeyline(
float offsetLoc,
@FloatRange(from = 0.0F, to = 1.0F) float mask,
float maskedItemSize,
boolean isFocal,
boolean isAnchor,
float cutoff,
float leftOrTopPaddingShift,
float rightOrBottomPaddingShift) {
if (maskedItemSize <= 0F) {
return this;
}
if (isAnchor) {
if (isFocal) {
throw new IllegalArgumentException("Anchor keylines cannot be focal.");
}
if (latestAnchorKeylineIndex != NO_INDEX && latestAnchorKeylineIndex != 0) {
throw new IllegalArgumentException(
"Anchor keylines must be either the first or last keyline.");
}
latestAnchorKeylineIndex = tmpKeylines.size();
}
Keyline tmpKeyline =
new Keyline(UNKNOWN_LOC, offsetLoc, mask, maskedItemSize, isAnchor, cutoff,
leftOrTopPaddingShift, rightOrBottomPaddingShift);
if (isFocal) {
if (tmpFirstFocalKeyline == null) {
tmpFirstFocalKeyline = tmpKeyline;
firstFocalKeylineIndex = tmpKeylines.size();
}
if (lastFocalKeylineIndex != NO_INDEX && tmpKeylines.size() - lastFocalKeylineIndex > 1) {
throw new IllegalArgumentException(
"Keylines marked as focal must be placed next to each other. There cannot be"
+ " non-focal keylines between focal keylines.");View on GitHub (pinned to ac7e18efee)
Solutions
- Use at most two anchors: one as the first keyline added and optionally one as the last; remove intermediate isAnchor=true flags.
- Order the builder calls so anchors are added before (first) and after (last) all other keylines.
- Print the add sequence of (isAnchor, isFocal, maskedItemSize) per keyline in a debug log to spot the stray anchor.
Example fix
// before builder.addKeyline(o0, m0, s0, false, true); // anchor builder.addKeyline(o1, m1, s1, false, false); builder.addKeyline(o2, m2, s2, false, true); // anchor after others -> throws // after builder.addKeyline(o0, m0, s0, false, true); // first anchor builder.addKeyline(o1, m1, s1, true, false); // focal builder.addKeyline(o2, m2, s2, false, true); // last anchor — index of previous anchor is 0, OK
Defensive patterns
Strategy: validation
Validate before calling
// Enforce: anchors only at index 0 and the final add boolean isFirstAdd = keylinesAddedSoFar == 0; boolean isLastAdd = (i == totalKeylines - 1); boolean anchor = isFirstAdd || isLastAdd; builder.addKeyline(offset, mask, size, focal, anchor);
Prevention
- Limit anchors to the first and last keylines added.
- Never mark interior keylines as anchors.
- Debug-log each (index, isAnchor) pair while building states.
When it happens
Trigger: Calling addKeyline(..., isAnchor=true) three or more times in one builder, or adding an anchor after non-anchor keylines when an earlier anchor is not at index 0 (e.g. first anchor added after some leading keylines). The anchor-after-anchor pattern that isn't first/last is what the latestAnchorKeylineIndex != 0 check catches.
Common situations: Custom CarouselStrategy code that marks every 'edge-ish' keyline as an anchor in a loop, or copies UncontainedCarouselStrategy-style anchors into a strategy whose keyline ordering differs, putting an anchor in the middle. Debugging is easier knowing the builder checks at add time, so the stack trace points at the exact offending addKeyline call.
Related errors
- Anchor keylines cannot be focal.
- Keylines marked as focal must be placed next to each other.
- Keylines that are marked as focal must all have the same mas
- Keylines before the first focal keyline must be ordered by i
- Keylines after the last focal keyline must be ordered by dec
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/ec57579479cd28aa.
Report an issue: GitHub.