{"record":{"id":"468540b569c20f83","repo":"material-components/material-components-android","slug":"anchor-keylines-cannot-be-focal","errorCode":null,"errorMessage":"Anchor keylines cannot be focal.","messagePattern":"Anchor keylines cannot be focal\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/carousel/KeylineState.java","lineNumber":385,"sourceCode":"     * @param cutoff How much the keyline item is out the bounds of the available space.\n     */\n    @NonNull\n    @CanIgnoreReturnValue\n    public Builder addKeyline(\n        float offsetLoc,\n        @FloatRange(from = 0.0F, to = 1.0F) float mask,\n        float maskedItemSize,\n        boolean isFocal,\n        boolean isAnchor,\n        float cutoff,\n        float leftOrTopPaddingShift,\n        float rightOrBottomPaddingShift) {\n      if (maskedItemSize <= 0F) {\n        return this;\n      }\n      if (isAnchor) {\n        if (isFocal) {\n          throw new IllegalArgumentException(\"Anchor keylines cannot be focal.\");\n        }\n        if (latestAnchorKeylineIndex != NO_INDEX && latestAnchorKeylineIndex != 0) {\n          throw new IllegalArgumentException(\n              \"Anchor keylines must be either the first or last keyline.\");\n        }\n        latestAnchorKeylineIndex = tmpKeylines.size();\n      }\n\n      Keyline tmpKeyline =\n          new Keyline(UNKNOWN_LOC, offsetLoc, mask, maskedItemSize, isAnchor, cutoff,\n              leftOrTopPaddingShift, rightOrBottomPaddingShift);\n      if (isFocal) {\n        if (tmpFirstFocalKeyline == null) {\n          tmpFirstFocalKeyline = tmpKeyline;\n          firstFocalKeylineIndex = tmpKeylines.size();\n        }\n\n        if (lastFocalKeylineIndex != NO_INDEX && tmpKeylines.size() - lastFocalKeylineIndex > 1) {","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/carousel/KeylineState.java#L367-L403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nbuilder.addKeyline(offset, mask, maskedSize, /* isFocal */ true, /* isAnchor */ true);\n\n// after\nbuilder.addKeyline(offset, mask, smallMaskedSize, /* isFocal */ false, /* isAnchor */ true); // edge anchor\nbuilder.addKeyline(offset2, 0f, itemSize, /* isFocal */ true, /* isAnchor */ false); // center focal","handlingStrategy":"validation","validationCode":"boolean anchor = isEdgePosition(i);\nboolean focal = !anchor && isFullSize(maskedItemSize);\nbuilder.addKeyline(offset, mask, maskedItemSize, focal, anchor);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["android","material-components","carousel","keylines","custom-strategy","builder"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}