{"record":{"id":"c04e46d0f08959ec","repo":"airbnb/lottie-android","slug":"you-must-provide-a-static-value-in-the-constructor-c04e46","errorCode":null,"errorMessage":"You must provide a static value in the constructor , call setValue, or override getValue.","messagePattern":"You must provide a static value in the constructor , call setValue, or override getValue\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lottie/src/main/java/com/airbnb/lottie/value/LottieRelativePointValueCallback.java","lineNumber":47,"sourceCode":"            frameInfo.getEndValue().x,\n            frameInfo.getInterpolatedKeyframeProgress()),\n        MiscUtils.lerp(\n            frameInfo.getStartValue().y,\n            frameInfo.getEndValue().y,\n            frameInfo.getInterpolatedKeyframeProgress())\n    );\n\n    PointF offset = getOffset(frameInfo);\n    point.offset(offset.x, offset.y);\n    return point;\n  }\n\n  /**\n   * Override this to provide your own offset on every frame.\n   */\n  public PointF getOffset(LottieFrameInfo<PointF> frameInfo) {\n    if (value == null) {\n      throw new IllegalArgumentException(\"You must provide a static value in the constructor \" +\n          \", call setValue, or override getValue.\");\n    }\n    return value;\n  }\n}\n","sourceCodeStart":29,"sourceCodeEnd":53,"githubUrl":"https://github.com/airbnb/lottie-android/blob/05ea92e90381eb8a8ae06855ea2b74f322bebbec/lottie/src/main/java/com/airbnb/lottie/value/LottieRelativePointValueCallback.java#L29-L53","documentation":"LottieRelativePointValueCallback adds an offset to the animation's interpolated PointF on every frame. Its default getOffset() returns the inherited `value` field, which is null unless supplied. The library throws IllegalArgumentException when the keyframe animation first evaluates this callback and finds `value == null`. Note the message text ('override getValue') is copy-pasted from the base class; for this relative callback the correct override is getOffset, and getValue is already declared final.","triggerScenarios":"Constructing `new LottieRelativePointValueCallback()` (no-arg) and registering it via addValueCallback on a position-typed LottieProperty (TRANSFORM_POSITION, POSITION, ELLIPSE_POSITION, etc.) without calling setValue or overriding getOffset. The throw occurs during BaseKeyframeAnimation value resolution on the first frame the property is needed, inside the draw pass.","commonSituations":"Using the Relative variant where plain LottieValueCallback<PointF> was intended (the Relative one requires an offset, not an absolute point); passing a PointF to setValue that was itself null; assuming getOffset returns PointF(0,0) by default; rebinding the callback to a different KeyPath at runtime after forgetting to re-initialize value; Lottie version change that no longer tolerates the uninitialized path.","solutions":["Supply the offset via constructor: `new LottieRelativePointValueCallback(new PointF(10f, 5f))`.","Or call `callback.setValue(new PointF(x, y))` before/while the animation runs to set or update the offset.","Or subclass and override `getOffset(LottieFrameInfo<PointF> frameInfo)` to return a computed PointF per frame (not getValue, which is final here).","Confirm the registered LottieProperty is point-typed; binding this callback to a non-point property yields the same null evaluation."],"exampleFix":"// before\nLottieRelativePointValueCallback cb = new LottieRelativePointValueCallback();\nanimationView.addValueCallback(keyPath, LottieProperty.TRANSFORM_POSITION, cb); // throws on first frame\n\n// after — option A: static offset point\nLottieRelativePointValueCallback cb =\n    new LottieRelativePointValueCallback(new PointF(0f, 50f));\n\n// after — option B: per-frame offset\ncb = new LottieRelativePointValueCallback() {\n  @Override\n  public PointF getOffset(LottieFrameInfo<PointF> frameInfo) {\n    return new PointF((float) Math.sin(frameInfo.getOverallProgress() * Math.PI * 2) * 20f, 0f);\n  }\n};","handlingStrategy":"validation","validationCode":"LottieRelativePointValueCallback cb;\nboolean ok;\ntry {\n  cb.getOffset(new com.airbnb.lottie.value.LottieFrameInfo<android.graphics.PointF>());\n  ok = true;\n} catch (IllegalArgumentException e) {\n  ok = false;\n}\nif (!ok) {\n  cb = new LottieRelativePointValueCallback(new android.graphics.PointF(0f, 0f));\n}","typeGuard":"// Enforce initialization through factories that require an offset or an override:\nstatic LottieRelativePointValueCallback offset(android.graphics.PointF p) {\n  return new LottieRelativePointValueCallback(p);\n}\nstatic LottieRelativePointValueCallback offset(java.util.function.Function<com.airbnb.lottie.value.LottieFrameInfo<android.graphics.PointF>, android.graphics.PointF> fn) {\n  return new LottieRelativePointValueCallback() {\n    @Override public android.graphics.PointF getOffset(com.airbnb.lottie.value.LottieFrameInfo<android.graphics.PointF> frameInfo) { return fn.apply(frameInfo); }\n  };\n}","tryCatchPattern":"// Programmer error — prefer to fix, not catch. Defensive isolation only:\ntry {\n  animationView.addValueCallback(keyPath, LottieProperty.TRANSFORM_POSITION, cb);\n  animationView.invalidate();\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"static value\")) {\n    cb.setValue(new android.graphics.PointF(0f, 0f));\n  } else { throw e; }\n}","preventionTips":["The Relative Point callback needs an OFFSET point, not an absolute position — don't confuse it with LottieValueCallback<PointF>.","Disallow the no-arg constructor in your codebase unless getOffset is overridden in the same expression.","Dry-test each callback: construct it and call getOffset(new LottieFrameInfo<>()) in a unit test before shipping.","Check the bound LottieProperty is point-typed; a mismatch still triggers the null evaluation.","During Lottie upgrades, smoke-test every screen using dynamic position callbacks on frame one."],"tags":["lottie","android","animation","value-callback","pointf","runtime"],"backgroundTag":null,"analyzedSha":"05ea92e90381eb8a8ae06855ea2b74f322bebbec","analyzedAt":"2026-08-14T00:51:35.636Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}