{"record":{"id":"acc01712efbcb946","repo":"airbnb/lottie-android","slug":"json-forbids-nan-and-infinities-at-path","errorCode":null,"errorMessage":"JSON forbids NaN and infinities: {} at path {}","messagePattern":"JSON forbids NaN and infinities: (.+?) at path (.+?)","errorType":"exception","errorClass":"JsonEncodingException","httpStatus":null,"severity":"error","filePath":"lottie/src/main/java/com/airbnb/lottie/parser/moshi/JsonUtf8Reader.java","lineNumber":690,"sourceCode":"      peekedString = nextQuotedValue(DOUBLE_QUOTE_OR_SLASH);\n    } else if (p == PEEKED_SINGLE_QUOTED) {\n      peekedString = nextQuotedValue(SINGLE_QUOTE_OR_SLASH);\n    } else if (p == PEEKED_UNQUOTED) {\n      peekedString = nextUnquotedValue();\n    } else if (p != PEEKED_BUFFERED) {\n      throw new JsonDataException(\"Expected a double but was \" + peek() + \" at path \" + getPath());\n    }\n\n    peeked = PEEKED_BUFFERED;\n    double result;\n    try {\n      result = Double.parseDouble(peekedString);\n    } catch (NumberFormatException e) {\n      throw new JsonDataException(\"Expected a double but was \" + peekedString\n          + \" at path \" + getPath());\n    }\n    if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {\n      throw new JsonEncodingException(\"JSON forbids NaN and infinities: \" + result\n          + \" at path \" + getPath());\n    }\n    peekedString = null;\n    peeked = PEEKED_NONE;\n    pathIndices[stackSize - 1]++;\n    return result;\n  }\n\n  /**\n   * Returns the string up to but not including {@code quote}, unescaping any character escape\n   * sequences encountered along the way. The opening quote should have already been read. This\n   * consumes the closing quote, but does not include it in the returned string.\n   *\n   * @throws IOException if any unicode escape sequences are malformed.\n   */\n  private String nextQuotedValue(ByteString runTerminator) throws IOException {\n    StringBuilder builder = null;\n    while (true) {","sourceCodeStart":672,"sourceCodeEnd":708,"githubUrl":"https://github.com/airbnb/lottie-android/blob/05ea92e90381eb8a8ae06855ea2b74f322bebbec/lottie/src/main/java/com/airbnb/lottie/parser/moshi/JsonUtf8Reader.java#L672-L708","documentation":"Thrown by nextDouble() when the parsed double value is NaN or Infinity and the reader is in strict (non-lenient) mode. Per the JSON specification (RFC 8259), NaN and Infinity are not valid JSON number literals — they are unquoted identifiers that strict parsers reject. Moshi enforces this unless setLenient(true) was called.","triggerScenarios":"The JSON contains a bare NaN, Infinity, or -Infinity token where a double is expected, and the reader is not in lenient mode. This can also occur if a numeric literal overflows double range (e.g., 1e999) producing Infinity via Double.parseDouble. The check at JsonUtf8Reader.java:689 triggers the throw at line 690.","commonSituations":"A Lottie JSON file exported from a tool that serializes JavaScript's NaN/Infinity directly into the JSON. A corrupted animation property where a computed value became NaN during export. Hand-edited JSON that inserted Infinity as a placeholder. Older Bodymovin versions that didn't sanitize special float values.","solutions":["Find the NaN/Infinity value in the JSON at the reported path and replace it with a valid finite number (e.g., 0.0 or the correct animation value)","Re-export from After Effects ensuring no expression evaluates to NaN/Infinity","If you control the JSON generation, sanitize: replace Double.isNaN/isInfinite values with 0.0 before serialization","If you must accept these, set the reader to lenient mode — but note Lottie's internal parser controls this and strict mode is intentional"],"exampleFix":"// before: {\"s\": [{\"x\": Infinity, \"y\": NaN}]}\n// after:  {\"s\": [{\"x\": 1.0, \"y\": 0.0}]}\n\n// if generating JSON yourself, sanitize before serializing:\ndouble safeVal = (Double.isNaN(val) || Double.isInfinite(val)) ? 0.0 : val;","handlingStrategy":"validation","validationCode":"// Sanitize NaN/Infinity values before loading\nString sanitizeJson(String json) {\n  // Replace bare NaN and Infinity tokens with 0\n  return json\n    .replaceAll(\"(?<![\\\\w\\\"])\\\\bNaN\\\\b(?![\\\\w\\\"])\", \"0\")\n    .replaceAll(\"(?<![\\\\w\\\"])-?\\\\bInfinity\\\\b(?![\\\\w\\\"])\", \"0\");\n}\n\n// Usage:\nString cleanJson = sanitizeJson(rawJson);\nLottieCompositionFactory.fromJsonData(cleanJson, cacheKey);","typeGuard":null,"tryCatchPattern":"try {\n  LottieCompositionFactory.fromJsonData(jsonData, cacheKey);\n} catch (JsonEncodingException e) {\n  // JSON forbids NaN and infinities\n  Log.w(TAG, \"Invalid numeric value in Lottie JSON: \" + e.getMessage());\n  // attempt to sanitize and retry, or fall back\n  showFallbackAnimation();\n}","preventionTips":["Ensure After Effects expressions never evaluate to NaN or Infinity before export","If generating Lottie JSON programmatically, sanitize special float values to 0.0 before serialization","Pre-validate JSON for bare NaN/Infinity tokens before passing to Lottie"],"tags":["json-parsing","moshi","lottie","numeric-overflow"],"backgroundTag":null,"analyzedSha":"05ea92e90381eb8a8ae06855ea2b74f322bebbec","analyzedAt":"2026-08-14T00:51:35.636Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}