{"record":{"id":"bdb347494120240c","repo":"airbnb/lottie-android","slug":"minframe-s-must-be-maxframe-s","errorCode":null,"errorMessage":"minFrame (%s) must be <= maxFrame (%s)","messagePattern":"minFrame \\((.+?)\\) must be <= maxFrame \\((.+?)\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lottie/src/main/java/com/airbnb/lottie/utils/LottieValueAnimator.java","lineNumber":197,"sourceCode":"      return;\n    }\n    this.frameRaw = MiscUtils.clamp(frame, getMinFrame(), getMaxFrame());\n    this.frame = useCompositionFrameRate ? ((float) Math.floor(frameRaw)) : frameRaw;\n    lastFrameTimeNs = 0;\n    notifyUpdate();\n  }\n\n  public void setMinFrame(int minFrame) {\n    setMinAndMaxFrames(minFrame, (int) maxFrame);\n  }\n\n  public void setMaxFrame(float maxFrame) {\n    setMinAndMaxFrames(minFrame, maxFrame);\n  }\n\n  public void setMinAndMaxFrames(float minFrame, float maxFrame) {\n    if (minFrame > maxFrame) {\n      throw new IllegalArgumentException(String.format(\"minFrame (%s) must be <= maxFrame (%s)\", minFrame, maxFrame));\n    }\n    float compositionMinFrame = composition == null ? -Float.MAX_VALUE : composition.getStartFrame();\n    float compositionMaxFrame = composition == null ? Float.MAX_VALUE : composition.getEndFrame();\n    float newMinFrame = MiscUtils.clamp(minFrame, compositionMinFrame, compositionMaxFrame);\n    float newMaxFrame = MiscUtils.clamp(maxFrame, compositionMinFrame, compositionMaxFrame);\n    if (newMinFrame != this.minFrame || newMaxFrame != this.maxFrame) {\n      this.minFrame = newMinFrame;\n      this.maxFrame = newMaxFrame;\n      setFrame((int) MiscUtils.clamp(frame, newMinFrame, newMaxFrame));\n    }\n  }\n\n  public void reverseAnimationSpeed() {\n    setSpeed(-getSpeed());\n  }\n\n  public void setSpeed(float speed) {\n    this.speed = speed;","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/airbnb/lottie-android/blob/05ea92e90381eb8a8ae06855ea2b74f322bebbec/lottie/src/main/java/com/airbnb/lottie/utils/LottieValueAnimator.java#L179-L215","documentation":"Thrown by LottieValueAnimator.setMinAndMaxFrames() when the minFrame parameter is greater than the maxFrame parameter. The frame range must be valid (min <= max) for the animator to produce a meaningful playback window. The check at line 196 (`minFrame > maxFrame`) guards against inverted ranges that would cause undefined playback behavior.","triggerScenarios":"Calling setMinAndMaxFrames(min, max) where min > max. This can also happen indirectly via setMinFrame(x) (which calls setMinAndMaxFrames(x, currentMaxFrame)) if x is greater than the current maxFrame, or via setMaxFrame(x) if x is less than the current minFrame. The throw is at LottieValueAnimator.java:197.","commonSituations":"Programmatically setting frame bounds with reversed arguments (min and max swapped). Calling setMinFrame() with a value larger than the current maxFrame without updating maxFrame first. Dynamic frame range calculation that produces an inverted range due to a logic error. Using user input or computed values without range validation.","solutions":["Ensure minFrame <= maxFrame before calling setMinAndMaxFrames(); validate or swap arguments if needed","When calling setMinFrame() or setMaxFrame() individually, ensure the new value doesn't cross the existing boundary — set both together if unsure","Use the composition's frame range as a reference: get it via LottieComposition.getStartFrame()/getEndFrame() to compute valid bounds"],"exampleFix":"// before: animator.setMinAndMaxFrames(60, 30);  // min > max\n// after:  int lo = Math.min(30, 60);\n//         int hi = Math.max(30, 60);\n//         animator.setMinAndMaxFrames(lo, hi);\n\n// or validate against composition bounds:\n// float compStart = composition.getStartFrame();\n// float compEnd = composition.getEndFrame();\n// float min = MiscUtils.clamp(requestedMin, compStart, compEnd);\n// float max = MiscUtils.clamp(requestedMax, min, compEnd);\n// animator.setMinAndMaxFrames(min, max);","handlingStrategy":"validation","validationCode":"// Validate frame range before setting\nvoid safeSetMinAndMaxFrames(LottieValueAnimator animator, float min, float max) {\n  if (min > max) {\n    throw new IllegalArgumentException(\n      \"minFrame (\" + min + \") must be <= maxFrame (\" + max + \")\");\n  }\n  animator.setMinAndMaxFrames(min, max);\n}\n\n// Or swap to ensure order:\nvoid setFramesSafe(LottieValueAnimator animator, float a, float b) {\n  float min = Math.min(a, b);\n  float max = Math.max(a, b);\n  animator.setMinAndMaxFrames(min, max);\n}","typeGuard":null,"tryCatchPattern":"try {\n  animator.setMinAndMaxFrames(minFrame, maxFrame);\n} catch (IllegalArgumentException e) {\n  Log.w(TAG, \"Invalid frame range: \" + e.getMessage());\n  // fall back to composition defaults\n  animator.setMinAndMaxFrame(composition);\n}","preventionTips":["Always ensure minFrame <= maxFrame before calling setMinAndMaxFrames","When updating one bound, be aware of the other bound's current value","Use Math.min/Math.max to normalize user-supplied frame values"],"tags":["lottie","animation","validation","frame-range"],"backgroundTag":null,"analyzedSha":"05ea92e90381eb8a8ae06855ea2b74f322bebbec","analyzedAt":"2026-08-14T00:51:35.636Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}