airbnb/lottie-android · error · JsonDataException

Expected a value but was {} at path {}

Error message

Expected a value but was {} at path {}

What it means

Thrown during skipValue() when a closing array bracket `]` (PEEKED_END_ARRAY) is encountered but the internal nesting counter has already reached zero (count < 0 at line 850). This means the JSON has an unbalanced bracket — there are more closing brackets than opening ones in the current scope being skipped.

Source

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

      throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath());
    }
    int count = 0;
    do {
      int p = peeked;
      if (p == PEEKED_NONE) {
        p = doPeek();
      }

      if (p == PEEKED_BEGIN_ARRAY) {
        pushScope(JsonScope.EMPTY_ARRAY);
        count++;
      } else if (p == PEEKED_BEGIN_OBJECT) {
        pushScope(JsonScope.EMPTY_OBJECT);
        count++;
      } else if (p == PEEKED_END_ARRAY) {
        count--;
        if (count < 0) {
          throw new JsonDataException(
              "Expected a value but was " + peek() + " at path " + getPath());
        }
        stackSize--;
      } else if (p == PEEKED_END_OBJECT) {
        count--;
        if (count < 0) {
          throw new JsonDataException(
              "Expected a value but was " + peek() + " at path " + getPath());
        }
        stackSize--;
      } else if (p == PEEKED_UNQUOTED_NAME || p == PEEKED_UNQUOTED) {
        skipUnquotedValue();
      } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_DOUBLE_QUOTED_NAME) {
        skipQuotedValue(DOUBLE_QUOTE_OR_SLASH);
      } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_SINGLE_QUOTED_NAME) {
        skipQuotedValue(SINGLE_QUOTE_OR_SLASH);
      } else if (p == PEEKED_NUMBER) {
        buffer.skip(peekedNumberLength);

View on GitHub (pinned to 05ea92e903)

Solutions

  1. Validate the JSON with a JSON linter or parser (e.g., jsonlint.com, or org.json in Java) before passing it to Lottie to detect structural errors
  2. Re-export the animation from After Effects to regenerate a well-formed JSON
  3. If the JSON is truncated, ensure the full file is downloaded/read before parsing — check network integrity and file completeness
  4. Catch JsonDataException during composition loading and show a fallback or error UI

Example fix

// before: {"k": [1, 2, 3]]}  // extra closing bracket
// after:  {"k": [1, 2, 3]}
Defensive patterns

Strategy: validation

Validate before calling

// Validate JSON structure balance before passing to Lottie
boolean isJsonStructurallyValid(String json) {
  try {
    new org.json.JSONObject(json); // or JSONArray if top-level is array
    return true;
  } catch (org.json.JSONException e) {
    // try as array
    try {
      new org.json.JSONArray(json);
      return true;
    } catch (org.json.JSONException e2) {
      return false;
    }
  }
}

Try / catch

try {
  LottieCompositionFactory.fromJsonData(jsonData, cacheKey);
} catch (JsonDataException e) {
  Log.w(TAG, "Structural error in Lottie JSON: " + e.getMessage());
  showFallbackAnimation();
}

Prevention

When it happens

Trigger: skipValue() is iterating through tokens and hits PEEKED_END_ARRAY when count is already 0. This happens when the JSON structure is malformed: an extra `]` appears, or a value was being skipped at the top level and the document structure is broken. The throw occurs at line 851.

Common situations: A truncated or corrupted Lottie JSON file where an array's closing bracket appears without a matching opening bracket. A minified JSON with missing brackets due to a transmission or encoding error. A Bodymovin plugin bug producing malformed array structures. Manual editing that removed an opening `[` but left the closing `]`.

Related errors


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