material-components/material-components-android · error · IllegalArgumentException
Anchor keylines cannot be focal.
Error message
Anchor keylines cannot be focal.
What it means
In KeylineState.Builder's keyline-add path (KeylineState.java:385), a keyline flagged isAnchor=true must not also be isFocal=true, so the builder throws IllegalArgumentException. Anchor keylines are the fixed reference points (typically the fully-revealed edge items) used when interpolating/rebuilding keyline states; focal keylines are the full-size center items. An anchor that is also focal would make the anchor's position depend on scroll focus, defeating its purpose as a stable reference.
Source
Thrown at lib/java/com/google/android/material/carousel/KeylineState.java:385
* @param cutoff How much the keyline item is out the bounds of the available space.
*/
@NonNull
@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) {View on GitHub (pinned to ac7e18efee)
Solutions
- Set isAnchor=true only on the small edge keylines and isFocal=true only on the center full-size keylines — never both on the same keyline.
- Model your builder calls on MultiBrowseCarouselStrategy's source, which shows the intended anchor/focal layout.
- If copying flag arrays between strategies, re-check each entry: anchors are typically the first and last keylines only.
Example fix
// before builder.addKeyline(offset, mask, maskedSize, /* isFocal */ true, /* isAnchor */ true); // after builder.addKeyline(offset, mask, smallMaskedSize, /* isFocal */ false, /* isAnchor */ true); // edge anchor builder.addKeyline(offset2, 0f, itemSize, /* isFocal */ true, /* isAnchor */ false); // center focal
Defensive patterns
Strategy: validation
Validate before calling
boolean anchor = isEdgePosition(i); boolean focal = !anchor && isFullSize(maskedItemSize); builder.addKeyline(offset, mask, maskedItemSize, focal, anchor);
Prevention
- Treat anchor and focal as mutually exclusive by construction.
- Copy flag patterns from MultiBrowseCarouselStrategy, not ad-hoc arrays.
- Unit-test custom strategies' keyline sequences (flags + sizes) in CI.
When it happens
Trigger: Calling KeylineState.Builder.addKeyline/addKeylineRange (from a custom CarouselStrategy) with isFocal=true and isAnchor=true for the same keyline — e.g. marking the large center keylines as anchors as well. Note the whole add is skipped (returns this) when maskedItemSize <= 0F, so the throw only occurs for positive-size keylines.
Common situations: Writing a custom CarouselStrategy and passing an isAnchor flag array or hardcoded booleans copied from another strategy without aligning which keylines are anchors vs focal. Unit-testing keyline construction with all-true flag arrays also trips it.
Related errors
- 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
- 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/468540b569c20f83.
Report an issue: GitHub.