airbnb/lottie-android · error · JsonDataException

Expected an int but was {} at path {}

Error message

Expected an int but was {} at path {}

What it means

Thrown by nextInt() when the peeked token was a PEEKED_LONG — a numeric literal that fit in a long — but casting it to int caused precision loss. This means the JSON number was outside the 32-bit signed integer range (-2,147,483,648 to 2,147,483,647). The check `peekedLong != result` at line 777 detects that the narrowing cast lost data.

Source

Thrown at lottie/src/main/java/com/airbnb/lottie/parser/moshi/JsonUtf8Reader.java:778

    }
  }

  private void skipUnquotedValue() throws IOException {
    long i = source.indexOfElement(UNQUOTED_STRING_TERMINALS);
    buffer.skip(i != -1L ? i : buffer.size());
  }

  @Override public int nextInt() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }

    int result;
    if (p == PEEKED_LONG) {
      result = (int) peekedLong;
      if (peekedLong != result) { // Make sure no precision was lost casting to 'int'.
        throw new JsonDataException("Expected an int but was " + peekedLong
            + " at path " + getPath());
      }
      peeked = PEEKED_NONE;
      pathIndices[stackSize - 1]++;
      return result;
    }

    if (p == PEEKED_NUMBER) {
      peekedString = buffer.readUtf8(peekedNumberLength);
    } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED) {
      peekedString = p == PEEKED_DOUBLE_QUOTED
          ? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
          : nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
      try {
        result = Integer.parseInt(peekedString);
        peeked = PEEKED_NONE;
        pathIndices[stackSize - 1]++;
        return result;

View on GitHub (pinned to 05ea92e903)

Solutions

  1. Inspect the JSON at the reported path and correct the oversized integer to a valid int-range value
  2. Re-export the animation from After Effects with a compatible Bodymovin version
  3. If consuming untrusted JSON, pre-validate integer fields against Integer range before handing to Lottie
  4. Catch the JsonDataException during composition loading to show a fallback instead of crashing

Example fix

// before: {"ind": 9999999999}  // asset index exceeds int range
// after:  {"ind": 0}
Defensive patterns

Strategy: validation

Validate before calling

// Check integer fields are within int range
boolean isSafeInt(long value) {
  return value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE;
}

// During JSON pre-validation:
void validateIntFields(org.json.JSONObject obj, String[] intFields) throws Exception {
  for (String field : intFields) {
    if (obj.has(field) && obj.get(field) instanceof Long) {
      long val = obj.getLong(field);
      if (!isSafeInt(val)) throw new IllegalStateException(field + " exceeds int range: " + val);
    }
  }
}

Try / catch

try {
  LottieCompositionFactory.fromJsonData(jsonData, cacheKey);
} catch (JsonDataException e) {
  if (e.getMessage().contains("Expected an int")) {
    Log.w(TAG, "Integer overflow in Lottie JSON: " + e.getMessage());
  }
  showFallbackAnimation();
}

Prevention

When it happens

Trigger: nextInt() is called on a JSON value that is a valid number but exceeds Integer.MAX_VALUE or is below Integer.MIN_VALUE. For example, a frame number, blend mode constant, or integer property that is unexpectedly large (e.g., 3000000000, or a timestamp in milliseconds). The throw occurs at JsonUtf8Reader.java:778.

Common situations: A Lottie JSON integer field contains an unexpectedly large value due to a Bodymovin plugin bug or misconfigured expression. A field that should be a small enum or index contains a garbage large number from a corrupted file. A version change in the export format using long timestamps or IDs where the Lottie parser expects an int.

Related errors


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