Changes to HttpService:JSONEncode and HttpService:JSONDecode

Hi Creators,

We will be modifying the behavior of the JSONEncode and JSONDecode methods on HttpService to add special encoding for inf/-inf/NaN values.

We will start rolling out this change on Mar 10, 2026. However, since we understand that this may break some games, we are offering the opportunity to opt-in early now or to opt-out until Apr 10, 2026. This can be done using the following opt-in/opt-out form.

This change will have no visible effect if you are using these APIs to transfer data exclusively between different Roblox APIs.

However, if you are using these APIs to send data to and from systems outside of Roblox, the impact may be transparent. The updated JSON data structure, which uses specific JSON object formats to represent inf, -inf, and NaN, is detailed below:

{
   "m": null,
   "t": "numeric",
   "v": "inf"
}

{
   "m": null,
   "t": "numeric",
   "v": "-inf"
}

{
   "m": null,
   "t": "numeric",
   "v": "NaN"
}

Example

{
   "myValue": inf		-- e.g. using math.huge or 1/0 in Luau
}

will now be encoded to:

{
   "myValue": {
      "m": null,
      "t": "numeric",
      "v": "inf"
   }
}

Creators using the HTTPService:JSONDecode API to decode the message will receive:

{
   "myValue": inf		-- e.g. using math.huge or 1/0 in Luau
}

Even after this change is shipped, the behavior should still be identical to what you would observe now.

Reason for this change

To improve performance, some internal services that utilize the output of the JSONEncode method will now require valid JSON content.

Currently, the system outputs values like inf and NaN. These are not standard JSON, but the existing implementation permits them.

To minimize data size, we use the single letters m, t, v to denote the special object marker, the data type, and the actual value, respectively.

What experiences does this change break?

This change could only break your experience if you are using HttpService:JSONEncode to generate an object to send to an external system.

If your usage of the outputted JSON already incorporates specific logic to handle these fields, such as inf and NaN, you may need to change this logic to recognize this new encoding format.

Updates to documentation will follow shortly.

As always, your feedback is invaluable for us to improve our services and fit your needs. Feel free to share any comments or questions below and we’ll do our best to answer!

Happy building!

The Roblox Creator Services Team

74 Likes

This topic was automatically opened after 10 minutes.

Why not just add like an extra parameter to JSONEncode and JSONDecode to allow toggling that behavior?

44 Likes

Thanks for this update! Good j*b Roblox Corporation!

Yes it can break a game and that’s the only bad thing

8 Likes

It would’ve been nice to test this by enabling a studio beta feature instead.

Anyways, does this affect JSON values that are set to null?

3 Likes

i don’t know what any of this does but if someone’s angry, I’M ANGRY

22 Likes

After running tests, see here, I need to partially correct my earlier post:

The new JSON only really under very niche conditions; however, there are grounds for which this could break decoding the data externally; specifically when using math.huge, -math.huge, or 0/0 (NaN) in data that is sent to external systems.

While the data can still be decoded back to its original form with some effort, this can been entirely avoided by introducing a parameter or a new, deprecated method (e.g., JSONEncode) instead of changing the behavior of the existing JSONEncode/JSONDecode calls, which I seriously hope is considered.

Original Post

GREAT GOING ROBLOX!!!

Now this’ll break any game that isn’t actively updated that uses JSONEncode for anything; including:

  1. Saving structured player data in DataStores as a serialized blob.
  2. Versioning player data formats for backward compatibility.
  3. Sending player stats or match results to external web backends.
  4. Receiving API responses from external services (authentication, inventory sync, moderation tools).
  5. Posting analytics events (economy transactions, session length, engagement metrics).
  6. Logging structured server events to a remote logging service.
  7. Communicating between servers using a custom external relay instead of only MessagingService.
  8. Storing and loading dynamic configuration data (shop inventories, balance values, event schedules).
  9. Exporting/importing player builds or game configurations in a shareable format.
  10. Saving user-generated content metadata (maps, presets, loadouts).
  11. Caching remote API responses locally in serialized form.
  12. Packaging complex state data for transmission through HttpService:PostAsync().
  13. Converting structured Lua tables into a format suitable for cloud databases.
  14. Storing structured audit trails for moderation review systems.
  15. Implementing external matchmaking systems that coordinate through a web service.
  16. Persisting serialized game state snapshots for debugging or replay systems.
  17. Encoding batched RemoteEvent payloads into a compact transferable structure.
  18. Integrating third-party services such as payment verification or ranking APIs.
  19. Migrating legacy data formats between different backend systems.
  20. Building external dashboards that read game-generated JSON data.

And more!

And you could’ve just made it a parameter! Or introduced a new version to call it and just deprecated the old call name! Great going!!!

Please at-least make it default opt-out :clap:

19 Likes

i looked closer in the reply, you literally just made the most basic numeric value calculator more complicated

3 Likes

To be clear, this will basically only affect you if you were already sending NaN/inf values and expecting them to be null. That, or you are allowing arbitrary JSON user input, which is something you both probably are not doing and was already made iffy by buffers becoming serializable.

You are making a mountain out of a molehill. This will break virtually nothing in practice.

23 Likes

Tell me you didn’t read the post without telling me you didn’t read the post…

Unless you’re decoding the data externally, AND have NaN/inf/-inf (bad practice to begin with) values in your data, then it will make no difference at all. It decodes back into the original data.

14 Likes

Almost none of those use cases are affected in practice. Especially not the ones that just pass it on to decode again. In fact they are improved.

And those for storing in cloud databases? If you’re storing in JSON then many of those would have broken/rejected the data with the old implementation, but now accept it properly, e.g. DynamoDB.

But I would be in favour of this just being an optional argument to those two methods.

I think defaulting to what Roblox has proposed is the sensible option, and if those unmaintained projects were handling inf/NaN unsafely then that’s their problem.

6 Likes

This change makes no sense. If you need this behavior for an internal Roblox API, then make a new API. Randomly adding some internal proprietary format for float numbers to JSONEncode results is very random and unexpected behavior
The whole POINT of JSONEncode is to talk to external services, who would use it if you’re not talking to external services??
I run backend services for my games and I do not expect for an object to randomly appear where a number is meant to be. I would prefer inf or nan getting turned to null rather than an object. I wouldn’t even mind if it errored! Since its not permitted in JSON. I just don’t want to see some random roblox proprietary format appearing in json sent to my backend.
Just for the record, tonumber(“inf”) returns inf, so if you are json encoding any sort of player input that you put through tonumber() after this change, you’ll all of a sudden have OBJECTS in your json output where you did not expect there to be. Saying NaN or inf is “bad practice” ignores the fact its LITERALLY A PART OF THE FLOATING POINT STANDARD, and also the fact tonumber() LITERALLY CAN RETURN IT.
This change will definitely be breaking to games which use databases or external services (not a niche thing!)
This should be a seperate internal API for whatever use case Roblox needs this for, it shouldn’t affect the API which is literally designed for external services (its LITERALLY in HTTPSERVICE)
Better yet, how about an ACTUAL JSON encoding / decoding API which has parameters, like enabling this proprietary format for floats, or enabling “pretty printing”? Thats something almost every language runtime has, but not Roblox! There can be a “floathandling” parameter which lets you choose how these values are handled (error, null, robloxformat)

13 Likes

My point isn’t about internal decoding. It’s about any time a game uses JSONEncode to send structured data outside of Roblox such as to Discord. the new {m,t,v} wrapper can break parsing. Internally it decodes back to the original, assuming the data never leaves Roblox.

Even though using NaN/inf/-inf is generally bad practice, there are real cases where games rely on them to track edge states, extreme metrics, or special flags.

Really Shit example but I suppose it applies

Let’s suppose a game has a logging system that is retrieving questionable action values (in reality the value would be stored in a separate script most likely and be accessed by conditional flag logic but this is to simplify)

local HttpService = game:GetService("HttpService")
local playerData = {
    playerId = 12345,
    suspiciousFlag = 10e9,  -- extreme amount flagged for review
}

HttpService:PostAsync("https://my-logger.com/bucket", HttpService:JSONEncode(playerData))

Before the change, this would serialize as:

"suspiciousFlag": 10000000000

Before this change that would have produced "suspiciousFlag": 10000000000. With the new behavior, if something becomes inf or NaN it becomes an object instead:

"suspiciousFlag": { "m": null, "t": "numeric", "v": "inf" }

Any external system expecting a plain numeric value would now fail to parse it, even though Roblox internally decodes it back to the original number.

I completely agree most of the time this won’t occur, but just because it’s rare doesn’t mean it shouldn’t be a concern for games that actually do send structured JSON externally.

3 Likes

No it won’t and I have no idea how you even figured that would be the case considering that is very much not inf. In any case where this change will be noticeable, it is in a place where nil would’ve been sent instead. You are making up reasons to be upset.

3 Likes

I meant to include that in reference to the example being provided. The scenario I’m describing is NOT about values that would become nil. It’s about extreme numeric values (very large numbers, or math.huge/NaN) that some games may log or send externally.

In those cases, the new {m,t,v} wrapper replaces a numeric literal in the JSON, which can break external parsers that expect a plain number.

If you want I can write up and record a demonstration of this behavior. I’m not trying to make up reasons to be upset but simply list genuine concerns with this new architecture.

2 Likes

The behavior will NOT affect “large numbers”. It affects inf. Inf is a very particular float, not just a large number.

The only case where you will see this change behavior is in places where it sent null before.

There is zero case with this change where code that used to send a number through JSON will now send the special object.

1 Like

if a user inputs “inf” and your code does tonumber() to it and sends it to backend (god forbid i did tonumber on user input, so insecure)
you’ll now have an object where there was meant to be a number in your backend. The main issue is this breaking existing code. If this was a thing before then it would probably be okay known behavior but adding a proprietary format to an existing api is bad imo

3 Likes

No you won’t. You were getting null. inf has no JSON representation. Try it right now:

print(game.HttpService:JSONEncode({ x = tonumber("inf") }))

Your code was already broken, or you already have some way to handle this. This is not realistic and the sky isn’t falling.

1 Like

Would love to know the performance benefits you guys saw from this—as I can’t imagine a 5% perf boost giving reason enough to make a breaking change. Sounds great though!

Yes, but null is better than a proprietary format the existing code doesn’t expect. tonumber() can return null. Existing code probably already accounts for it. It does not expect an object with a proprietary format

2 Likes