{"record":{"id":"d18aa21099cb8001","repo":"airbnb/lottie-android","slug":"cannot-interpolate-between-gradients-lengths-vary","errorCode":null,"errorMessage":"Cannot interpolate between gradients. Lengths vary ({} vs {})","messagePattern":"Cannot interpolate between gradients\\. Lengths vary \\((.+?) vs (.+?)\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lottie/src/main/java/com/airbnb/lottie/model/content/GradientColor.java","lineNumber":45,"sourceCode":"    return colors.length;\n  }\n\n  public void lerp(GradientColor gc1, GradientColor gc2, float progress) {\n    // Fast return in case start and end is the same\n    // or if progress is at start/end or out of [0,1] bounds\n    if (gc1.equals(gc2)) {\n      copyFrom(gc1);\n      return;\n    } else if (progress <= 0f) {\n      copyFrom(gc1);\n      return;\n    } else if (progress >= 1f) {\n      copyFrom(gc2);\n      return;\n    }\n\n    if (gc1.colors.length != gc2.colors.length) {\n      throw new IllegalArgumentException(\"Cannot interpolate between gradients. Lengths vary (\" +\n          gc1.colors.length + \" vs \" + gc2.colors.length + \")\");\n    }\n\n    for (int i = 0; i < gc1.colors.length; i++) {\n      positions[i] = MiscUtils.lerp(gc1.positions[i], gc2.positions[i], progress);\n      colors[i] = GammaEvaluator.evaluate(progress, gc1.colors[i], gc2.colors[i]);\n    }\n\n    // Not all keyframes that this GradientColor are used for will have the same length.\n    // AnimatableGradientColorValue.ensureInterpolatableKeyframes may add extra positions\n    // for some keyframes but not others to ensure that it is interpolatable.\n    // If there are extra positions here, just duplicate the last value in the gradient.\n    for (int i = gc1.colors.length; i < positions.length; i++) {\n      positions[i] = positions[gc1.colors.length - 1];\n      colors[i] = colors[gc1.colors.length - 1];\n    }\n  }\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/airbnb/lottie-android/blob/05ea92e90381eb8a8ae06855ea2b74f322bebbec/lottie/src/main/java/com/airbnb/lottie/model/content/GradientColor.java#L27-L63","documentation":"GradientColor.lerp() interpolates between two gradient color stops element-by-element. Before the lerp loop, it asserts gc1.colors.length == gc2.colors.length; if the two gradients have a different number of color entries, it throws IllegalArgumentException. The source comments note that AnimatableGradientColorValue.ensureInterpolatableKeyframes() is supposed to pad gradients so all keyframes share the same color count — if that normalization step fails or is bypassed, this guard fires.","triggerScenarios":"The Lottie JSON defines a gradient animation where keyframes have inconsistent numbers of gradient color stops (e.g., one keyframe has 3 colors and another has 5). This also occurs if lerp() is called directly on two GradientColor instances constructed with mismatched array lengths, bypassing the ensureInterpolatableKeyframes normalization.","commonSituations":"Hand-edited or programmatically generated Lottie JSON with inconsistent gradient definitions across keyframes; corrupted animation files exported from tools that don't normalize gradient stop counts; calling GradientColor.lerp() directly in custom drawing code with manually constructed GradientColor objects.","solutions":["Ensure all keyframes for a given gradient property define the same number of color stops. Re-export the animation from After Effects / LottieFiles with consistent gradient settings.","If calling lerp() directly, pre-normalize both GradientColor instances to the same length by copying positions/colors and padding with the last value.","Check that AnimatableGradientColorValue.ensureInterpolatableKeyframes() was invoked during parsing (it runs automatically for standard LottieComposition parsing); if you construct GradientColor objects outside the parser, replicate that normalization logic."],"exampleFix":"// before — direct lerp with mismatched lengths\nGradientColor gc1 = new GradientColor(pos3, colors3); // 3 stops\nGradientColor gc2 = new GradientColor(pos5, colors5); // 5 stops\nresult.lerp(gc1, gc2, 0.5f); // throws\n\n// after — normalize to the larger size before lerping\nint maxLen = Math.max(gc1.getSize(), gc2.getSize());\nGradientColor normGc1 = gc1.copyWithPositions(paddedPositions(maxLen, gc1));\nGradientColor normGc2 = gc2.copyWithPositions(paddedPositions(maxLen, gc2));\nresult.lerp(normGc1, normGc2, 0.5f);","handlingStrategy":"validation","validationCode":"// Validate gradient color counts before lerping\npublic static boolean canLerp(GradientColor gc1, GradientColor gc2) {\n    return gc1.getSize() == gc2.getSize();\n}","typeGuard":null,"tryCatchPattern":"try {\n    result.lerp(gc1, gc2, progress);\n} catch (IllegalArgumentException e) {\n    // Gradient stop counts differ — fall back to nearest keyframe\n    result.copyFrom(progress < 0.5f ? gc1 : gc2);\n}","preventionTips":["Ensure all gradient keyframes in the Lottie animation define the same number of color stops.","If constructing GradientColor objects manually, always normalize to the same length before calling lerp().","Trust the library's built-in ensureInterpolatableKeyframes() normalization for standard LottieComposition parsing."],"tags":["lottie","gradient","interpolation","animation-data","illegal-argument"],"backgroundTag":null,"analyzedSha":"05ea92e90381eb8a8ae06855ea2b74f322bebbec","analyzedAt":"2026-08-14T00:51:35.636Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}