Unexpected Number in JSON: Every Cause and Fix
SyntaxError: Unexpected number in JSON at position 1 is the quieter cousin of "Unexpected token in JSON" โ same parser, same one-line message, but the culprit is almost always a number written the way a human would write it and not the way the JSON grammar requires. A zip code, a leading plus sign, a stray decimal point: JSON's number rules are stricter than JavaScript's, and every version of "close enough" fails the same way. This guide covers every real-world cause, the exact browser message each one produces, and the fix, with a live, prefilled JSON Lab example for each.
Unexpected number, you almost certainly have a number with a leading zero โ 01, 007, a US zip code like 02134. JSON allows a lone 0, but never a multi-digit number that starts with one. Other malformed-number messages (Unterminated fractional number, Exponent part is missing a number, or a plain Unexpected token naming + or .) point at a different broken number shape, covered below.
Quick reference
Messages below are what current Chrome, Edge, and Node.js (all V8) actually print — verified by pasting each example into JSON Lab. Firefox and Safari phrase some of these differently, but the underlying cause and fix are the same everywhere.
| What V8 prints | Most likely cause | Fix |
|---|---|---|
Unexpected number in JSON at position N | A number has a leading zero (01, 02134) | Quote it as a string, or drop the leading zero |
Unexpected token '+' ... is not valid JSON | A number has an explicit leading plus sign | Remove the + — JSON numbers are positive by default |
Unexpected token '.' ... is not valid JSON | A number starts with . instead of a digit | Add the leading 0 (0.99, not .99) |
Unterminated fractional number in JSON | A number ends in . with no digit after it | Drop the trailing . or add a digit |
Exponent part is missing a number in JSON | An e/E exponent has no digits after it | Add the exponent digits, or drop the e |
Unexpected token 'N'/'I' ... is not valid JSON | The literal NaN or Infinity was written into the JSON | Use null — JSON has no NaN or Infinity |
Expected ',' or '}' after property value in JSON | A hex literal like 0xFF was written into the JSON | Convert to decimal, or quote it as a string |
1. A leading zero
The single most common cause. JSON's number grammar permits exactly one digit before a non-zero leading digit: either the number is 0 by itself, or its first digit is 1–9. There's no rule for "a zero followed by more digits," so the parser reads the 0, then hits a second digit it has no grammar rule for and gives up right there — which is why the position reported is one character after where the number actually starts.
JSON.parse('{"zipCode": 02134, "id": 5}');
// Unexpected number in JSON at position 13 (line 1 column 14)
This bites hardest on values that look numeric but have a meaningful leading zero: US zip codes, French department codes, phone extensions, employee IDs padded to a fixed width. Storing any of these as a JSON number is already the wrong call even when the input happens to parse — JSON.stringify({zip: 02134}) would silently produce {"zip":1116} in old non-strict JS, or a syntax error in modern JS, because 02134 itself isn't valid in a JavaScript source file either once strict mode is on.
// Fixed: quote it, since the leading zero is meaningful
JSON.parse('{"zipCode": "02134", "id": 5}');
See it fail live
This is a zip code written as a bare number — the exact shape that produces the error above.
Open this example in JSON Lab2. An explicit leading plus sign
JavaScript number literals accept a unary + (+72 is the same value as 72). JSON's grammar has no unary plus at all — the only sign a JSON number can carry is a single leading -. This shows up when JSON is hand-assembled from a template that always writes a sign, or when a value copied from a signal/sensor feed keeps its explicit polarity marker.
JSON.parse('{"temperature": +72, "unit": "F"}');
// Unexpected token '+', "...erature": +72, "unit"... is not valid JSON
// Fixed: no sign on a positive number
JSON.parse('{"temperature": 72, "unit": "F"}');
See it fail live
Open this example in JSON Lab3. A number that starts with a decimal point
JavaScript happily evaluates .99 as 0.99. JSON requires at least one digit before the decimal point — there's no grammar rule for a fraction with nothing in front of it, so the parser fails on the . itself rather than reading any of the digits after it.
JSON.parse('{"price": .99, "currency": "USD"}');
// Unexpected token '.', "{"price": .99, "curr"... is not valid JSON
// Fixed: leading zero required
JSON.parse('{"price": 0.99, "currency": "USD"}');
See it fail live
Open this example in JSON Lab4. A trailing decimal point with nothing after it
The mirror image of the last one: a decimal point with no fractional digits following it. This is easy to introduce with naive string concatenation — code that appends . whenever a value "might" have a fraction, then appends nothing else when it turns out to be a whole number.
JSON.parse('{"version": 2., "stable": true}');
// Unterminated fractional number in JSON at position 14 (line 1 column 15)
// Fixed: either drop the dot, or add a digit
JSON.parse('{"version": 2.0, "stable": true}');
See it fail live
Open this example in JSON Lab5. An exponent with no digits
JSON supports scientific notation (1e10, 2.5E-3), but the exponent marker e/E must always be followed by at least one digit, optionally preceded by a sign. Truncated input — a value cut off mid-string, or a template that writes the e before it knows the exponent — leaves the marker dangling.
JSON.parse('{"count": 1e, "scale": "large"}');
// Exponent part is missing a number in JSON at position 12 (line 1 column 13)
// Fixed: either supply the exponent, or drop the 'e'
JSON.parse('{"count": 1, "scale": "large"}');
See it fail live
Open this example in JSON Lab6. NaN or Infinity written literally
Both are legal JavaScript number values, and neither exists in the JSON specification. This is precisely why JSON.stringify() converts NaN, Infinity, and -Infinity to null automatically — the spec authors knew there was nowhere else for them to go. The error only shows up when JSON is built by hand instead — a template literal or string concatenation that interpolates a number directly, skipping JSON.stringify entirely. If the interpolated value happens to be NaN (a failed parseFloat, a division by zero, a missing field in a calculation), String(NaN) is the four-character text NaN, and that text lands in the output verbatim.
const score = someCalculation(); // returns NaN on bad input
const payload = `{"score": ${score}, "max": ${maxScore}}`; // string concat, not JSON.stringify
JSON.parse(payload);
// Unexpected token 'N', "{"score": NaN, "max""... is not valid JSON
// Fixed: build the object and let JSON.stringify handle it
const payload = JSON.stringify({ score, max: maxScore });
// NaN becomes null automatically โ no hand-written template needed
See it fail live
Open this example in JSON Lab7. A hexadecimal literal copied from JavaScript source
JavaScript accepts 0xFF5733 as a number literal. JSON's number grammar is decimal only — there's no hex, octal, or binary prefix anywhere in the spec. This one usually comes from copying a color value, a bitmask, or a memory address straight out of source code into what's meant to be a JSON config or API payload, without converting it to a decimal number or a string first.
JSON.parse('{"color": 0xFF5733}');
// Expected ',' or '}' after property value in JSON at position 11 (line 1 column 12)
The parser reads the leading 0 as a complete, valid number on its own, then expects a comma or closing brace next — and finds the letter x instead, which is why this one surfaces as a different message than the others on this page even though the root cause is the same family of mistake.
// Fixed: decimal number, or a quoted hex string if the format matters
JSON.parse('{"color": 16734003}'); // 0xFF5733 in decimal
JSON.parse('{"color": "#FF5733"}');
See it fail live
Open this example in JSON LabDebugging checklist
- Check the position the error reports against the raw string — with number errors it usually lands one character past where the bad number actually starts, since the parser has to read at least one valid digit first.
- If the value came from user input or an external feed (zip codes, IDs, phone numbers), ask whether it should be a JSON string instead of a JSON number — anything with a meaningful leading zero belongs in quotes.
- If the JSON was hand-assembled with string concatenation or a template literal instead of
JSON.stringify(), that's the real bug: switch toJSON.stringify()and this entire class of error stops being possible. - Paste the exact raw string into a formatter with a real parser and tree view, not a regex-based "JSON-ish" checker — you want the same engine and the same error your production code hits.
๐งช Paste your broken JSON and see the real error
JSON Lab runs the same parser your browser does — formatting, syntax validation and every example above happen entirely client-side, with nothing uploaded. Two buttons are the exception: AI Repair sends your current input to Gemini to generate a suggested fix, and Validate Schema sends both your JSON and schema to Gemini for the logical check. Skip those two for anything sensitive and stick to manual fixes from this guide instead.
Open JSON Lab โ