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
- Inspect the JSON at the reported path and correct the oversized integer to a valid int-range value
- Re-export the animation from After Effects with a compatible Bodymovin version
- If consuming untrusted JSON, pre-validate integer fields against Integer range before handing to Lottie
- 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
- Validate integer-range fields in the JSON before loading
- Re-export from After Effects to fix corrupt integer values
- Log the reported value and path to trace which field overflows
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
- JSON forbids NaN and infinities: {} at path {}
- Expected a value but was {} at path {}
- End of input
- Unterminated escape sequence at path {}
- Unknown trim path type {}
AI-assisted analysis of airbnb/lottie-android@05ea92e903 (2026-08-14).
Data as JSON: /api/errors/ba093f4cd3fae25a.
Report an issue: GitHub.