• Categories
  • Recent
  • Tags
  • Popular
  • Solved
  • Unsolved
  • Users
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Darkly)
  • No Skin
Collapse
brainCloud Forums

Newtonsoft.Json fails to deserialize integer fields after BrainCloud SDK upgrade 5.9.3

Scheduled Pinned Locked Moved Unsolved General
11 Posts 4 Posters 34 Views
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    LEE JONG GUN
    wrote last edited by LEE JONG GUN
    #1

    Environment:

    Unity (C#)
    BrainCloud SDK 5.9.3 (upgraded from 5.9.2)
    Issue:
    After upgrading to BrainCloud SDK 5.9.3, integer values from cloud code script responses are converted to floats before being passed to the success callback.

    Details:

    The server-side cloud code script explicitly assigns integer values: var tier = 7;
    The server JSON response correctly contains "tier": 7 (integer)
    Before SDK 5.9.3: The callback received "tier": 7 (integer, as expected)
    After SDK 5.9.3: The callback receives "tier": 7.0 (float, unexpected)
    The SDK internally parses and re-serializes the response (likely related to the new JsonParser introduced in 5.9.3??), converting integers to floats in the process
    This breaks JsonConvert.DeserializeObject<T>() when the target field is int, throwing: JsonReaderException: Input string '7.0' is not a valid integer
    Only affects custom values set in cloud code scripts. BrainCloud's own API values (e.g. rank, score) are not affected.
    Expected Behavior:
    Integer values from cloud code scripts should remain as integers in the callback response string, same as SDK 5.9.

    1 Reply Last reply
    0
  • Steve JonesS Offline
    Steve JonesS Offline
    Steve Jones brainCloudAdmin
    wrote last edited by
    #2

    Hey @LEE-JONG-GUN Thanks for reaching out,

    For us to better support and uncover the issue you are raising, can you provide the appId, and profileId of the user that this occurred on? Can you send this information through the support widget, instead of in the public forum.

    This will help us analyze the response and requests and confirm the payload and data being int to float.

    -= Steve Jones =-

    1 Reply Last reply
    0
  • Paul WinterhalderP Offline
    Paul WinterhalderP Offline
    Paul Winterhalder brainCloudAdmin
    wrote last edited by
    #3

    Hi Lee,

    We are having difficulties recreating the issue.

    Can you post an example JSON response where you are seeing the issue... it may help us to track down what it causing it...

    Thanks,

    Paul.

    1 Reply Last reply
    0
  • Steve JonesS Offline
    Steve JonesS Offline
    Steve Jones brainCloudAdmin
    wrote last edited by
    #4

    Great news — we've been able to dig into this and have a better picture of what's going on with the client_tier vs. stage_rank behavior.

    Here's what we found: stage_rank is defined as an integer in the leaderboard scores response payload, so it comes through cleanly. However, client_tier originates from a Cloud Script Number value, which is treated internally as a double — meaning it can come across with a trailing .0 (e.g., 1.0 instead of 1).

    In the past, this was silently handled during serialization/deserialization on the client side. But since the optimized client no longer goes through that process, that .0 is no longer being stripped before the data reaches your callbacks.

    In the meantime, here's a quick fix: If you're on version 5.9.3, running the response through a JSON serializer/deserializer — such as JsonParser, Newtonsoft.Json, or Unity's JsonUtility — should clean up that reading path and resolve the issue. There may be a disadvantage in using LitJson.JsonMapper for this case, which presents this as a double, instead of an int like the other object parsers.

    We're also actively exploring longer-term solutions to make this more robust on our end, potentially through a configuration option or a fix at the source, so you don't have to work around it manually.

    Let us know if you have any questions or run into anything else — happy to help!

    -= Steve Jones =-

    1 Reply Last reply
    0
  • L Offline
    L Offline
    LEE JONG GUN
    wrote last edited by
    #5

    Ok I will try Thank you!

    1 Reply Last reply
    0
  • Paul WinterhalderP Offline
    Paul WinterhalderP Offline
    Paul Winterhalder brainCloudAdmin
    wrote last edited by
    #6

    Hi @LEE-JONG-GUN - did you have any luck with that?

    1 Reply Last reply
    0
  • Paul WinterhalderP Offline
    Paul WinterhalderP Offline
    Paul Winterhalder brainCloudAdmin
    wrote last edited by
    #7

    Note - the client devs have asked me to point out that this serialization challenge is only for folks using LitJson. All the other libs seem to handle things just fine.

    L 2 Replies Last reply
    0
  • L Offline
    L Offline
    LEE JONG GUN
    replied to Paul Winterhalder last edited by
    #8

    @Paul-Winterhalder Thanks for the clarification.

    At the moment, I have not finished retesting everything yet
    because I am handling several other tasks in parallel.
    However, to give you an accurate answer, I am currently
    reinstalling and testing again on 5.9.3.

    For reference, this issue is not occurring with LitJson on
    our side. The deserialization error is happening with
    Newtonsoft.Json.JsonConvert.

    More importantly, the root problem is not just which JSON
    library is being used. The actual issue is that the raw
    response itself is already coming through differently.
    Before, this value came through as an integer, but in 5.9.3
    it is coming through as a double-form value such as 7.0.

    So from our perspective, the problem starts at the raw
    response level, before deserialization into our class.

    1 Reply Last reply
    0
  • L Offline
    L Offline
    LEE JONG GUN
    replied to Paul Winterhalder last edited by
    #9

    @Paul-Winterhalder 스크린샷 2026-03-14 오전 12.58.39.png

    The error we are seeing is:

    JsonReaderException: Input string '4.0' is not a valid integer. Path 'tier', line 2

    I tried the approach you suggested.

    I parsed the response with JObject first and then
    deserialized it again using JsonConvert.DeserializeObject.

    However, the error remains the same.

    JsonReaderException: Input string '4.0' is not a valid integer.

    It appears that the raw response value is already coming
    through as a double (e.g. 4.0). When Newtonsoft.Json tries
    to deserialize it into an int field, it fails.

    So simply passing the response through a
    serializer/deserializer step does not seem to resolve the
    issue in this case.

    Michael CostaM 1 Reply Last reply
    0
  • Michael CostaM Online
    Michael CostaM Online
    Michael Costa
    replied to LEE JONG GUN last edited by Michael Costa
    #10

    Hello @LEE-JONG-GUN!

    So looking into JsonConvert it looks like it actually uses LitJson underneath the hood 🤔

    So one option to replicate the old functionality is to use BrainCloud.JsonFx.Json.JsonReader to deserialize into Dictionary<string, object> and then BrainCloud.JsonFx.Json.JsonWriter back into a string before having JObject.Parse() use it. This is basically what the old behaviour was and it would strip out trailing .0 values from JS Numbers.

    SuccessCallback successCallback = (response, cbObject) =>
    {
        response = JsonWriter.Serialize(JsonReader.Deserialize(response)); // Replicate the old BCComms behaviour
    
        DisplayLog(string.Format("Success | {0}", response));
        JObject jsonData = JObject.Parse(response);
    
        if (jsonData["data"]["response"] != null && jsonData["status"].ToString() == "200")
        {
            scoreData = JsonConvert.DeserializeObject<ScoreData>(jsonData["data"]["response"].ToString()); // This should be working now as JsonWriter will strip trailing .0 from doubles
            // ...
        }
        // ...
    }
    

    Although you could also just use JsonReader instead of JsonConvert as this should also strip the trailing .0 so you don't have to waste CPU cycles on the serialization/deserialization:

    scoreData = JsonReader.Deserialize<ScoreData>(jsonData["data"]["response"].ToString());
    

    Alternatively you can also bypass using JObjects and JsonConvert in this situation and make use of our BrainCloud.Common.JsonParser together with JsonReader like so:

    SuccessCallback successCallback = (response, cbObject) =>
    {
        DisplayLog(string.Format("Success | {0}", response));
    
        if (JsonParser.GetString(response, "data", "response") is string responseData &&
            !string.IsNullOrEmpty(responseData) &&
            JsonParser.GetValue<int>(response, "status") == 200) // JsonParser can grab strings directly without having to do object memory allocations
        {
            scoreData = JsonReader.Deserialize<ScoreData>(responseData);
            // ...
        }
        // ...
    }
    

    I think JsonParser can be handy for grabbing strings of json objects, json arrays, and values directly without having to do memory allocations 😃

    Let us know if any of these solutions work for you!

    L 1 Reply Last reply
    0
  • L Offline
    L Offline
    LEE JONG GUN
    replied to Michael Costa last edited by
    #11

    @Michael-Costa

        string responseData = JsonParser.GetString(response, "data", "response");
            if (!string.IsNullOrEmpty(responseData) &&    JsonParser.GetValue<int>(response, "status") == 200){
    
                ScoreData3 scoreData = JsonReader.Deserialize<ScoreData3>(responseData);
                Debug.LogError(scoreData.stage_rank); >>WORKING
                Debug.LogError(scoreData.tier);>>WORKING
    

    We tested using the method you suggested, and with that approach
    the double values started coming through as integers correctly.

    However, another issue appeared because we are using Obscured
    Values in our project.

    When deserializing classes that contain Obscured types, those
    fields are not converted correctly with this method.

    The error we get is:

    InvalidCastException: Invalid cast from 'System.String'
    to 'CodeStage.AntiCheat.ObscuredTypes.ObscuredString'.

    If we switch back to using a JsonConverter, the original double
    problem happens again.

    Currently we resolve the Obscured type conversion using:

    JsonConvert.DefaultSettings = () =>
    new JsonSerializerSettings {
    Converters = { new ObscuredTypesNewtonsoftConverter() }
    };

    So my question is: does JsonReader provide a way to apply a
    converter globally in a similar way, like JsonConvert.DefaultSettings?

    1 Reply Last reply
    0

  • Login

  • Login or register to search.
  • First post
    Last post
0
  • Categories
  • Recent
  • Tags
  • Popular
  • Solved
  • Unsolved
  • Users