Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crash: JsonUtf8Reader.nextInt #2552

Open
MKelman opened this issue Sep 24, 2024 · 9 comments
Open

crash: JsonUtf8Reader.nextInt #2552

MKelman opened this issue Sep 24, 2024 · 9 comments

Comments

@MKelman
Copy link

MKelman commented Sep 24, 2024

Describe the bug
I am receiving this crash (full crash log attached)

Fatal Exception: java.lang.IllegalStateException: Unable to parse composition
at com.airbnb.lottie.LottieAnimationView.lambda$static$0(LottieAnimationView.java:72)
at com.airbnb.lottie.LottieAnimationView$1.onResult(LottieAnimationView.java:84)
at com.airbnb.lottie.LottieAnimationView$1.onResult(LottieAnimationView.java:77)

What version of Lottie did you test this on?
6.5.0

What version of Android did you test this on?
occurring on all android versions

image

Steps To Reproduce
Steps to reproduce the behavior:

  1. go to https://app.lottiefiles.com/
  2. make lottie
  3. download image image
  4. when we upload that image and view it, there are decimals.. so we have to undecimal it?

stacktrace

com.adfone.aditup_issue_9ca65e77d3c3d036d7f1f31e48bb3ef8_crash_session_66F2F4BD0327000166560C71E2CFFAE2_DNE_0_v2_stacktrace.txt

example lottie file downloaded
blue_progress_bar_corrected.json

@gpeal
Copy link
Collaborator

gpeal commented Sep 29, 2024

That animation is parsing fine for me and the stack trace you provided doesn't seem to line up with the code in Lottie 6.5.0
https://github.com/airbnb/lottie-android/blob/v6.5.0/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java#L242

As a result, it isn't clear to me which property you have that has decimals that is currently parsed as an int. Can you provide more information?

CleanShot.2024-09-28.at.23.02.57.mp4

@MKelman
Copy link
Author

MKelman commented Sep 30, 2024

@gpeal I made a mistake, here is the bad json. I gave you the correccted, chat gpt json, that your website spitted out.

blue_progress_bar.json

If you look at the top layer of the crash,
Caused by l1.a: Expected an int but was 501.999 at path $.layers[10].h
at com.airbnb.lottie.parser.moshi.JsonUtf8Reader.nextInt(JsonUtf8Reader.java:815)

this ( com.airbnb.lottie.parser.moshi.JsonUtf8Reader.nextInt(JsonUtf8Reader.java:815)) occurs here https://github.com/airbnb/lottie-android/blob/v6.5.0/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java#L242 and that

which seems like it doesn't like doubles? If you review the json i attached, its full of doubles in there. Does that makes sense
image

@MKelman
Copy link
Author

MKelman commented Oct 14, 2024

Hi @gpeal have you been able to look into this?

@gpeal
Copy link
Collaborator

gpeal commented Oct 14, 2024

@MKelman Not yet! I support Lottie on nights and weekends but will do my best to find some time for this. Feel free to take a look yourself and put up a PR if you'd like though.

@MKelman
Copy link
Author

MKelman commented Oct 14, 2024

Sounds good, appreciate it! Wasn't sure if the "needs more info" flag was the reason you didn't see this yet. If I get a chance, I'll try to look myself as well :) But let me be clear, I dont believe the issue may be on android, I believe it may be part of the web tool that spits out decimal place results. But I'll see what else I can find If i have the time

@gpeal
Copy link
Collaborator

gpeal commented Oct 27, 2024

@MKelman The second animation you attached also parses fine. I'm trying reverse engineer what your issue is and it still isn't clear:

  1. Your stack trace points to LayerParser line 242 which is a break statement.
  2. From the error Caused by l1.a: Expected an int but was 501.999 at path $.layers[10].h, I think it might actually be this line which is already parsed as a double.

Can you provide more info?

@JuHyang
Copy link

JuHyang commented Nov 15, 2024

I encountered a similar issue, and after investigating, I believe the reason is as follows:

The root cause of the intermittent exceptions when parsing a double value like 796.05 in the nextInt() method likely stems from floating-point precision errors. In Java (and Android), floating-point numbers are not always stored with exact precision, especially for values with decimal places. As a result, 796.05 might be stored internally as something slightly different, such as 796.0499999... or 796.0500001..., which can lead to inconsistencies during parsing.

Here’s how these precision issues can lead to intermittent behavior:

Floating-Point Precision Variability
When 796.05 is parsed through Double.parseDouble(peekedString), it may be stored as 796.0499999.... Casting this to int will yield 796. However, if the parsed value happens to be slightly closer to 796.0500001..., the casted int will still be 796, but the comparison in nextInt() (result != asDouble) might fail, triggering an exception.

Inconsistent Comparison Results
Due to these floating-point precision issues, the comparison between the int-casted value and the original double can intermittently pass or fail, depending on how closely the parsed double aligns with its intended value.

These floating-point precision limitations seem to be the underlying cause of the intermittent exceptions.

@MiJey
Copy link

MiJey commented Nov 22, 2024

Hello @gpeal,

I’ve analyzed the issue and would like to share my findings below.

If the fractional part of asDouble is not 0, the check result != asDouble below will throw a JsonDataException.
For example, if asDouble is 796.05, result becomes 796, and the check result != asDouble evaluates to true because 796.00 != 796.05, resulting in an exception.

It appears that this condition was added under the assumption that Lottie JSON files would not contain numbers with decimal points (this is my personal assumption).
However, some JSON files generated by the editor provided by LottieFiles include numbers with decimal points.

Differences of 1 pixel in values like width or height are almost imperceptible to the eye. Therefore, we chose to ignore such minor precision issues and commented out the condition.

Below is the actual code we commented out:

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

    int result;
    // ... (omitted)

    peeked = PEEKED_BUFFERED;
    double asDouble;
    try {
      asDouble = Double.parseDouble(peekedString);
    } catch (NumberFormatException e) {
      throw new JsonDataException("Expected an int but was " + peekedString
          + " at path " + getPath());
    }
    result = (int) asDouble;
    /*
    if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
      throw new JsonDataException("Expected an int but was " + peekedString
          + " at path " + getPath());
    }
    */
    peekedString = null;
    peeked = PEEKED_NONE;
    pathIndices[stackSize - 1]++;
    return result;
  }

Could you modify the library to ensure it does not throw an exception when Lottie JSON files include numbers with decimal points?

@gpeal
Copy link
Collaborator

gpeal commented Nov 22, 2024

@MiJey That makes sense, the issue is more around which properties are being exported as doubles. The original implementation here was written when After Effects was the only platform and it always exported whole numbers and width/height. Now that there are other exporters, it looks like some of them behave differently.

I can update layer width/height to be a double (that looks like the property with the issue here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants