airbnb/lottie-android · error · IllegalArgumentException

You must provide a static value in the constructor , call se

Error message

You must provide a static value in the constructor , call setValue, or override getValue.

What it means

Thrown by LottieRelativeFloatValueCallback.getOffset() when the internal value field is null. This callback is designed to add a relative offset to the animation's interpolated value, but it needs a base offset value to work with. The value can be set via the constructor (passing a Float), via setValue(), or by overriding getOffset()/getValue() entirely. If none of these are done, getOffset() has no offset to return and throws.

Source

Thrown at lottie/src/main/java/com/airbnb/lottie/value/LottieRelativeFloatValueCallback.java:34

  public LottieRelativeFloatValueCallback(@NonNull Float staticValue) {
    super(staticValue);
  }

  @Override
  public Float getValue(LottieFrameInfo<Float> frameInfo) {
    float originalValue = MiscUtils.lerp(
        frameInfo.getStartValue(),
        frameInfo.getEndValue(),
        frameInfo.getInterpolatedKeyframeProgress()
    );
    float offset = getOffset(frameInfo);
    return originalValue + offset;
  }

  public Float getOffset(LottieFrameInfo<Float> frameInfo) {
    if (value == null) {
      throw new IllegalArgumentException("You must provide a static value in the constructor " +
          ", call setValue, or override getValue.");
    }
    return value;
  }
}

View on GitHub (pinned to 05ea92e903)

Solutions

  1. Pass a static offset value to the constructor: new LottieRelativeFloatValueCallback(0.5f)
  2. Call setValue(offset) on the callback instance before or during animation
  3. Override getOffset(LottieFrameInfo<Float>) in a subclass to compute the offset dynamically without needing a static value
  4. If you want absolute value control (not relative), use LottieValueCallback<Float> instead of LottieRelativeFloatValueCallback

Example fix

// before:
// LottieRelativeFloatValueCallback<Float> cb = new LottieRelativeFloatValueCallback<>();
// lottieAnimationView.addValueCallback(keyPath, property, cb);  // throws on first frame

// after option 1: provide a static offset in the constructor
// LottieRelativeFloatValueCallback cb = new LottieRelativeFloatValueCallback(0.5f);

// after option 2: call setValue
// cb.setValue(0.5f);

// after option 3: override getOffset for dynamic offset
LottieRelativeFloatValueCallback cb = new LottieRelativeFloatValueCallback() {
  @Override public Float getOffset(LottieFrameInfo<Float> frameInfo) {
    return frameInfo.getInterpolatedKeyframeProgress() * 100f; // dynamic
  }
};
Defensive patterns

Strategy: validation

Validate before calling

// Ensure value is set before using the callback
LottieRelativeFloatValueCallback createSafeCallback(float offset) {
  return new LottieRelativeFloatValueCallback(offset); // non-null static value
}

// Or validate before use:
void ensureValueSet(LottieRelativeFloatValueCallback cb) {
  if (cb.getValue(new LottieFrameInfo<>()) == null && !hasOverride(cb)) {
    cb.setValue(0f); // provide a default offset
  }
}

Type guard

// Check if the callback has a usable value before applying
boolean isCallbackReady(LottieRelativeFloatValueCallback cb) {
  try {
    cb.getOffset(new LottieFrameInfo<Float>());
    return true;
  } catch (IllegalArgumentException e) {
    return false;
  }
}

Try / catch

try {
  lottieAnimationView.addValueCallback(keyPath, property, callback);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("static value")) {
    callback.setValue(0f); // provide default offset
    lottieAnimationView.addValueCallback(keyPath, property, callback);
  } else throw e;
}

Prevention

When it happens

Trigger: Creating a LottieRelativeFloatValueCallback with the no-arg constructor (new LottieRelativeFloatValueCallback()) and using it as a value callback without calling setValue() or overriding getOffset(). When Lottie evaluates the animation and calls getValue() -> getOffset(), the null check at line 33 fires the throw at line 34.

Common situations: A developer creates the callback with the no-arg constructor intending to override getOffset() later but forgets. Subclassing LottieRelativeFloatValueCallback and not overriding getOffset() or providing a value. Copying example code that used the constructor overload but switching to no-arg. Refactoring that removed a setValue() call.

Related errors


AI-assisted analysis of airbnb/lottie-android@05ea92e903 (2026-08-14). Data as JSON: /api/errors/bc62169ba41bc529. Report an issue: GitHub.