JSON Syntax Errors: Guesswork vs Evidence-Led Fixes

Start With the Response, Not the Request

Before you touch a single line of fetch code, paste your API endpoint URL directly into a JSON validator tool. If the server is returning malformed JSON — trailing commas, unquoted keys, single quotes wrapping strings — no amount of client-side debugging will save you. I learned this the hard way after spending 45 minutes rewriting a fetch chain only to discover the backend was concatenating JSON fragments without proper array brackets.

Here's the workflow that cuts debugging time dramatically: open your browser DevTools Network tab, reproduce the fetch call, click the response payload, copy it, and run it through a JSON linter. The linter will pinpoint the exact character position of the syntax error. That position number is your single most valuable clue.

Stop Assuming fetch Throws on Bad JSON

This is the mistake I see in roughly 8 out of 10 codebases I review. Developers write something like this:

fetch('/api/users').then(res => res.json()).then(data => console.log(data))

They expect the promise chain to reject if the JSON is broken. It won't. The fetch() promise only rejects on network failures — DNS errors, connection refused, CORS blocked. A server returning HTTP 200 with the text {"name": "John",} is considered a successful request. The rejection happens later, inside res.json(), and if you don't catch it there, you get an unhandled promise rejection with a message like Unexpected token } that tells you almost nothing useful.

The Fix: Wrap json() Parsing Explicitly

Separate the response status check from the JSON parsing step. This gives you two distinct failure points to investigate:

const res = await fetch('/api/users'); if (!res.ok) throw new Error('HTTP ' + res.status); const text = await res.text(); let data; try { data = JSON.parse(text); } catch (e) { console.error('Parse error at position:', e.message); console.log('Raw response:', text.substring(0, 200)); throw e; }

Notice I'm using res.text() first, then JSON.parse() manually. This lets you log the raw payload when parsing fails. That raw output is what you paste into your JSON formatter tool to see exactly where the structure breaks.

Don't Trust the Error Message Line Number

When res.json() throws SyntaxError: Unexpected token N in JSON at position 142, developers often jump to line 142 of their source file. Wrong. That position refers to character 142 within the JSON string itself, not your JavaScript file. This distinction matters enormously when you're debugging a 3,000-character API response.

The position number tells you where the parser choked. But the actual syntax error often lives several characters earlier — an unclosed quote, a missing comma, an unescaped newline. The parser keeps consuming tokens until it hits something impossible, then reports that position. So if position 142 says "unexpected token," start scanning backward from character 142.

Using a JSON Validator to Find the Real Error

Take the raw response text and paste it into a JSON syntax checker. Most quality JSON tools will highlight the exact character and explain the violation in plain language: "Expected property name but found '}'" or "String literals must use double quotes." This is infinitely more actionable than the V8 engine's terse Unexpected token message.

I've debugged responses where the validator caught errors the browser parser didn't even report correctly — specifically, cases where a backend was serving JSON with BOM characters prepended. The fetch parser saw \uFEFF{"name":"John"} and threw a generic syntax error at position 0. The JSON validator flagged the BOM explicitly.

Check Your Headers Before Blaming the Payload

Servers sometimes return valid JSON with the wrong Content-Type header. If the response arrives as text/html instead of application/json, certain HTTP clients and proxies may mangle the payload before it reaches your fetch handler. I tracked down one production bug where a CDN was HTML-encoding quotes in JSON responses because the origin server sent Content-Type: text/html. Every double quote became ", breaking every string boundary in the payload.

Always inspect response headers in the Network tab. If Content-Type isn't application/json or application/json; charset=utf-8, that's your first suspect — even before you look at the payload itself.

Handle Trailing Commas — The Silent Killer

Trailing commas are valid in JavaScript objects and arrays. They are not valid in JSON. This mismatch causes more syntax errors than any other single issue I encounter. A backend developer writes {"name": "John", "role": "admin",} in their server code, the framework serializes it, and your fetch call receives JSON that technically violates RFC 8259.

JavaScript's JSON.parse() strictly rejects trailing commas. But here's the subtle part: some backend frameworks have lenient serializers that produce trailing commas in edge cases — typically when an optional field is conditionally included and the serialization logic doesn't clean up the final comma.

The Debugging Steps

Copy the raw JSON response into a formatter tool that supports strict RFC 8259 validation. If the tool reports a trailing comma, you have two options: fix the backend serializer, or preprocess the response on the client side with a regex like text.replace(/,\s*([}\]])/g, '$1') before parsing. The regex approach is a bandage, not a cure — but it'll unblock your frontend while the backend fix ships.

Decode Escaped Characters Properly

JSON strings must escape certain characters: double quotes, backslashes, and control characters. When a database field contains a literal backslash — say, a Windows file path like C:\Users\John — and the backend doesn't double-escape it, the JSON becomes {"path":"C:\Users\John"}. The parser sees \U and \J as invalid escape sequences.

This error surfaces as Bad escaped character or Unexpected token U depending on your JavaScript engine. The fix is always server-side: ensure the serializer properly escapes backslashes. On the client, you can identify this class of error by searching the raw response text for single backslashes that aren't followed by valid escape characters: ", \, /, b, f, n, r, t, or u.

Log the Raw Text Every Time

Build this habit into your fetch wrapper permanently. Before any JSON parsing happens, log the first 500 characters of the response text to the console. When a syntax error occurs, you'll have immediate visibility into what the server actually sent — not what you assumed it sent. I keep a utility function in every project that does exactly this:

async function safeFetch(url, options) { const res = await fetch(url, options); const text = await res.text(); if (process.env.NODE_ENV !== 'production') { console.log('Response preview:', text.substring(0, 500)); } try { return JSON.parse(text); } catch (e) { console.error('JSON parse failed:', e.message); console.error('Full response:', text); throw new Error('Invalid JSON from ' + url + ': ' + e.message); } }

This wrapper has saved me countless hours. When a third-party API starts returning HTML error pages with a 200 status — another surprisingly common failure mode — the response preview immediately shows <!DOCTYPE html> instead of {, and the root cause is obvious before you even look at the parse error.

Validate Before You Ship

Every JSON payload your application produces should pass through a validator during development. If you're building a JSON tool or API client, integrate validation into your test suite. Run sample responses through a strict JSON parser in your CI pipeline. Catch syntax errors before they reach production fetch calls, where debugging means reading server logs at 2 AM instead of clicking a validator in your browser.

The developers who debug fastest aren't the ones who write the cleverest code. They're the ones who build visibility into every layer of the fetch cycle — headers, raw text, parse errors, and validation — so when something breaks, the evidence is already on screen.

Frequently Asked Questions

How do I fix the "Unexpected token < in JSON at position 0" error in fetch?

This error usually occurs when your fetch API call receives HTML (like a 404 page) instead of the expected JSON data. To fix it, check your API endpoint URL and log the raw response using response.text() to see exactly what the server is returning.

Why does response.json() throw a syntax error in JavaScript?

The response.json() method throws a syntax error when the response body is not perfectly formatted as valid JSON. This often happens if the server sends an empty response, truncated data, or an unexpected data type like plain text or HTML.

How can I catch JSON parsing errors in a fetch API call?

You can catch these errors by wrapping your response.json() call in a try...catch block or by appending a .catch() to your fetch promise chain. This prevents your JavaScript application from crashing when the API returns invalid JSON.

What does "Unexpected end of JSON input" mean in a fetch response?

This error means the server returned an empty string or a severely truncated JSON string that cannot be parsed. Check your server-side code to ensure it is actually sending a complete JSON payload before the connection closes.

How do I check if a fetch response is valid JSON before parsing?

Before calling response.json(), check the Content-Type header using response.headers.get('Content-Type') to ensure it includes application/json. Alternatively, call response.text() first and run it through a JSON validator tool or a safe JSON.parse() wrapper.

How do I see the raw response body when JSON parsing fails?

Instead of immediately calling response.json(), call response.text() to read the raw response body as a string. You can then log this string to the console to inspect the exact formatting issues or server errors causing the JSON syntax failure.

How do I handle API errors that return text instead of JSON?

You should inspect the response.ok property and the Content-Type header to determine if the request was successful. If the response is not OK, parse the text instead of JSON to display a meaningful error message to the user.

Can I use a JSON validator tool to debug fetch API responses?

Yes, copying the raw text output from your response.text() call and pasting it into an online JSON validator is a quick way to find missing commas or unclosed brackets. These tools highlight the exact line number and character where the syntax error occurs.

How do I debug a "SyntaxError: Unexpected token" in JSON?

This error indicates a specific character is breaking the JSON structure, such as a trailing comma, single quotes, or an unescaped character. Log the raw response text and use a JSON formatter to pinpoint the exact position of the syntax error.