{"record":{"id":"6648680e6b5f189d","repo":"material-components/material-components-android","slug":"keylines-being-linearly-interpolated-must-have-the-664868","errorCode":null,"errorMessage":"Keylines being linearly interpolated must have the same number of keylines.","messagePattern":"Keylines being linearly interpolated must have the same number of keylines\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/carousel/KeylineState.java","lineNumber":193,"sourceCode":"  }\n\n  /**\n   * Linearly interpolate between two {@link KeylineState}s.\n   *\n   * @param from the start keyline state\n   * @param to the end keyline state\n   * @param progress the interpolation between from and to. When progress is 0, from will be\n   *     returned. When progress is 1, to will be returned.\n   */\n  static KeylineState lerp(KeylineState from, KeylineState to, float progress) {\n    if (from.getItemSize() != to.getItemSize()) {\n      throw new IllegalArgumentException(\n          \"Keylines being linearly interpolated must have the same item size.\");\n    }\n    List<Keyline> fromKeylines = from.getKeylines();\n    List<Keyline> toKeylines = to.getKeylines();\n    if (fromKeylines.size() != toKeylines.size()) {\n      throw new IllegalArgumentException(\n          \"Keylines being linearly interpolated must have the same number of keylines.\");\n    }\n\n    List<Keyline> keylines = new ArrayList<>();\n    for (int i = 0; i < from.getKeylines().size(); i++) {\n      keylines.add(Keyline.lerp(fromKeylines.get(i), toKeylines.get(i), progress));\n    }\n\n    int focalKeylineFirstIndex =\n        AnimationUtils.lerp(\n            from.getFirstFocalKeylineIndex(), to.getFirstFocalKeylineIndex(), progress);\n    int focalKeylineLastIndex =\n        AnimationUtils.lerp(\n            from.getLastFocalKeylineIndex(), to.getLastFocalKeylineIndex(), progress);\n\n    return new KeylineState(\n        from.getItemSize(),\n        keylines,","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/carousel/KeylineState.java#L175-L211","documentation":"The second precondition in KeylineState.lerp (KeylineState.java:193): the two interpolated states must contain the same number of keylines, because lerping walks both lists index-by-index. Mismatched counts (with equal item sizes) throw IllegalArgumentException. Count mismatches arise when the two states were produced by different keyline configurations — e.g. different strategy outputs or different container sizes producing different keyline counts.","triggerScenarios":"Library-internal lerping between a previous KeylineState (built before a configuration change) and a freshly calculated one whose addKeyline calls produced a different count — commonly caused by a custom CarouselStrategy whose keyline count depends on width, executed across a container resize, or by switching strategies at runtime.","commonSituations":"Custom strategies with count-varying math (e.g. 'fit as many keylines as width allows') returning different counts across rotations or fold/unfold transitions. Debug builds with different itemSpacing than release intermittently crashing only at specific widths. Like error 32, the crash appears during animation/measure, disconnected from the producing code.","solutions":["Make the custom strategy's keyline count deterministic and stable across the two states being lerped — derive counts from the KeylineStateList/API contract (use KeylineState.Builder with addKeylineRange for stable counts).","Rebuild both states from the same configuration before triggering transitions instead of reusing an old state.","If strategy switching at runtime is required, prefer refreshing keylines without lerping (set new state directly) rather than animating between incompatible states."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (from.getKeylines().size() == to.getKeylines().size() && from.getItemSize() == to.getItemSize()) {\n  KeylineState.lerp(from, to, progress);\n}","typeGuard":null,"tryCatchPattern":"try { KeylineState.lerp(from, to, progress); } catch (IllegalArgumentException e) { return to; // skip animation, snap to target }","preventionTips":["Make keyline counts deterministic per configuration in custom strategies.","Use addKeylineRange so counts stay stable.","Avoid lerping between states from different strategies; set the new state directly."],"tags":["android","material-components","carousel","keylines","animation","custom-strategy"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}