DEV Community

Cover image for Your JSON minifier might be silently corrupting large integers—here's the fix
Tripurari Ray for DigiTechGenAI

Posted on

Your JSON minifier might be silently corrupting large integers—here's the fix

If you work with database IDs, Snowflake IDs, or any large integers in JSON payloads, here's a bug worth knowing about.

Most JSON minifiers — including a lot of popular online ones — minify like this:

js

const minified = JSON.stringify(JSON.parse(input));
Enter fullscreen mode Exit fullscreen mode

Try it with a large integer:

js

JSON.parse('{"id": 9007199254740993}')
// { id: 9007199254740992 }

Enter fullscreen mode Exit fullscreen mode

That's 9007199254740993 (one past Number.MAX_SAFE_INTEGER) silently becoming 9007199254740992. No error, no warning—the output is still syntactically valid JSON; it's just not equal to what you gave it. If that ID gets used downstream—a lookup, a foreign key, an API call—you get a bug that's genuinely miserable to trace back to "the JSON got minified at some point."

The fix: don't round-trip through JSON.parse/JSON.stringify for the output. Minify at the character level instead:

js

function minifyPreservingLiterals(raw) {
  let out = '', inString = false, escaped = false;
  for (const ch of raw) {
    if (inString) {
      out += ch;
      if (escaped) escaped = false;
      else if (ch === '\\') escaped = true;
      else if (ch === '"') inString = false;
      continue;
    }
    if (ch === '"') { inString = true; out += ch; continue; }
    if (' \n\r\t'.includes(ch)) continue;
    out += ch;
  }
  return out;
}
Enter fullscreen mode Exit fullscreen mode

You can still use JSON.parse separately just to validate the input and surface a clear error message—you just don't use its output for the actual minified result. This way whitespace gets stripped, but every number literal (and every string, unchanged) survives exactly as written.

I built this into a free online JSON minifier—character-level minification, byte-perfect number preservation, optional key sorting, file upload/URL loading, and everything runs client-side (nothing is uploaded).

I'm curious if anyone's hit this in production before finding out why—it feels like one of those bugs that's invisible until it really isn't.

Top comments (0)