How to Fix Unexpected Token in JSON -- Real Developer Solutions

The first time I saw Unexpected token < in JSON at position 0, I spent three hours debugging what turned out to be a simple authentication issue. The API was returning a login page instead of JSON data.

This guide shares the debugging strategies I developed after years of dealing with these errors. You will learn not just how to fix them, but how to prevent them entirely.

Understanding the Error

When you see an "unexpected token" error, the JSON parser encountered something it did not expect at a specific position in your string.

The most common tokens that cause issues:

  • Less-than sign (from HTML responses)
  • Letter o (from [object Object])
  • Closing brace or bracket (from trailing commas)
  • End of file (from unterminated strings)

Each of these tells a different story about what went wrong.

Cause #1: Parsing an Object Instead of String

The Error

SyntaxError: Unexpected token o in JSON at position 1

What Actually Happened

That "o" is not random. It is the second character of [object Object]. You are passing a JavaScript object to JSON.parse() instead of a string.

I see this constantly in code reviews:

// Wrong
const obj = { name: "John" };
JSON.parse(obj); // Error!

// Right
const str = "{\"name\": \"John\"}";
JSON.parse(str); // Works!

Why This Keeps Happening

Two scenarios where this bites developers:

1. Double-parsing API responses

Your HTTP client already parsed the JSON, but you call JSON.parse() again:

// axios automatically parses JSON
const response = await axios.get("/api/user");
const user = JSON.parse(response.data); // ERROR! Already an object

// Just use it directly
const user = response.data; // Correct

2. Confusing variables

You stringify an object, then accidentally try to parse the original:

const obj = { key: "value" };
const str = JSON.stringify(obj);

JSON.parse(obj);   // ERROR - obj is not a string
JSON.parse(str);   // Works - str is a JSON string

My Fix

I now check the type before parsing:

if (typeof data === "string") {
  return JSON.parse(data);
}
return data;

This simple check has saved me countless debugging sessions.

Cause #2: Server Returns HTML Instead of JSON

The Error

SyntaxError: Unexpected token < in JSON at position 0

What Actually Happened

The less-than sign comes from an HTML tag like <!DOCTYPE html> or <html>. Your code expects JSON, but the server returned HTML.

This is arguably the most frustrating JSON error because the problem is not in your JSON at all.

Common Scenarios

From my experience, these are the usual suspects:

1. Authentication failures

User session expired, server redirects to login page:

fetch("/api/protected-data")
  .then(res => res.json()) // ERROR: Tries to parse HTML login page

2. Wrong API endpoint

Typo in URL returns 404 error page:

fetch("/api/usrs") // Should be "/api/users"
  .then(res => res.json()) // ERROR: Gets 404 HTML page

3. Server errors

Backend crashes and returns error page instead of JSON.

4. CDN or rate limiting

Cloudflare bot protection pages are HTML, not JSON.

How I Debug This

Step 1: Inspect the raw response

Always log the response before parsing:

const response = await fetch("/api/data");
const text = await response.text();

console.log("Status:", response.status);
console.log("Content-Type:", response.headers.get("content-type"));
console.log("First 200 chars:", text.substring(0, 200));

This instantly reveals if you are getting HTML, plain text, or malformed JSON.

Step 2: Check the Network tab

Open browser DevTools, go to Network tab, find the request:

  • Status code (should be 200, not 401/403/404/500)
  • Response headers (Content-Type: application/json)
  • Response body preview (is it HTML?)

Step 3: Add proper error handling

I now wrap all API calls with validation:

async function fetchJSON(url) {
  const response = await fetch(url);
  
  // Check status first
  if (!response.ok) {
    throw new Error("HTTP " + response.status + ": " + response.statusText);
  }
  
  // Verify content type
  const contentType = response.headers.get("content-type");
  if (!contentType || !contentType.includes("application/json")) {
    const text = await response.text();
    throw new Error("Expected JSON, got " + contentType + ": " + text.substring(0, 100));
  }
  
  return response.json();
}

This catches issues early and gives meaningful error messages instead of cryptic parse errors.

Cause #3: Trailing Commas

The Error

SyntaxError: Unexpected token } in JSON at position X

What Actually Happened

JSON does not allow trailing commas, but JavaScript does. This valid JavaScript breaks in JSON:

{
  "name": "John",
  "age": 30,
}

The comma after 30 is invalid in JSON.

Why This Confuses Everyone

JavaScript object literals allow trailing commas since ES2017. We get used to this convenience, then copy into .json files or API payloads, and everything breaks.

My Fix

Remove trailing commas manually, or use our JSON Formatter which removes them automatically.

Better yet, generate JSON programmatically:

const obj = {
  name: "John",
  age: 30
};

const json = JSON.stringify(obj, null, 2);
// Result never has trailing commas

Cause #4: Unterminated Strings

The Error

SyntaxError: Unexpected end of JSON input

What Actually Happened

A string is missing its closing quote:

{
  "message": "Hello world,
  "status": "ok"
}

The parser keeps reading, expecting more content, but hits the end instead.

Where This Comes From

Manual editing mistakes

Hand-editing large JSON files and accidentally deleting a quote. In a 500-line config file, finding that missing quote is painful.

String building bugs

// Do not build JSON manually
const json = "{\"name\": \"" + name + "\"}"; // Breaks if name contains quotes

Copy-paste errors

Copying JSON from documentation and missing the last character.

How I Fix It

Use our JSON Validator to instantly find unterminated strings. It highlights the exact line number where the parser expected a closing quote.

For large files, this is infinitely faster than manual scanning.

Cause #5: Invalid Escape Sequences

The Error

SyntaxError: Unexpected token in JSON at position X

What Actually Happened

Certain characters must be escaped in JSON strings:

  • Backslash: double backslash
  • Double quote: backslash quote
  • Newline: backslash n
  • Tab: backslash t

The classic mistake? Windows file paths:

{
  "path": "C:\new_folder\test.txt"
}

The parser interprets \n as newline and \t as tab, breaking the JSON.

My Fix

Option 1: Escape properly

{
  "path": "C:\\new_folder\\test.txt"
}

Option 2: Use forward slashes

{
  "path": "C:/new_folder/test.txt"
}

Node.js and most Windows APIs accept forward slashes.

Option 3: Let JSON.stringify handle it

const path = "C:\\new_folder\\test.txt";
const json = JSON.stringify({ path });
// Result: {"path":"C:\\new_folder\\test.txt"}

When generating JSON programmatically, escaping happens automatically.

My Debugging Workflow

Here is my step-by-step approach when I hit a JSON parse error:

Step 1: Inspect Raw Response

Always log the raw response before parsing:

const text = await response.text();
console.log(text);

This reveals if you are getting HTML, plain text, or malformed JSON. Nine times out of ten, the problem becomes obvious immediately.

Step 2: Validate Externally

Paste the response into our JSON Validator. It shows:

  • Exact error location (line and column)
  • Visual highlighting of syntax issues
  • Plain English explanation
  • All processing in your browser (no data sent anywhere)

For huge payloads (larger than 10MB), use jq:

cat large-file.json | jq .

jq is dramatically faster than browser tools for large files.

Step 3: Check Headers

Verify the Content-Type header:

response.headers.get("content-type")

Expected: application/json

If you get text/html, the server is not returning JSON.

Step 4: Add Error Handling

Wrap parsing in try-catch blocks:

try {
  const data = JSON.parse(responseText);
  console.log("Parsed successfully");
} catch (error) {
  console.error("Parse failed:", error.message);
  console.log("Raw response:", responseText);
}

This prevents crashes and gives you debuggable error messages.

Prevention Tips

After years of dealing with these errors, here is what I do to prevent them:

1. Never Build JSON Manually

Always use JSON.stringify():

// Bad
const json = "{\"name\": \"" + name + "\"}";

// Good
const json = JSON.stringify({ name: name });

JSON.stringify() handles all escaping, quoting, and formatting. It never produces invalid JSON.

2. Validate API Responses

Check status codes and content types before parsing:

if (!response.ok) {
  throw new Error("HTTP " + response.status);
}

const contentType = response.headers.get("content-type");
if (!contentType.includes("application/json")) {
  throw new Error("Expected JSON");
}

3. Use Linters

Configure your editor to validate JSON files automatically. Most modern editors have JSON linting built in.

4. Test with Validators

Before deploying configuration files, test them with validators to catch issues early.

Tools Comparison

| Tool | Best For | Privacy | |------|----------|---------| | VSCode | Medium payloads | Local | | jq | CLI workflows | Local | | Postman | API testing | Local | | Online formatters | Quick checks | Varies |

Choose tools that process data locally to protect sensitive information.

Our JSON Formatter and JSON Validator both run entirely in your browser -- no data leaves your machine.

FAQ

What does unexpected token mean?

It means the JSON parser found a character it did not expect at that position in the string. The error message includes the position number, which helps locate the issue.

How do I fix unexpected token errors?

  1. Check the raw response (log it before parsing)
  2. Validate with external tools like JSON Validator
  3. Verify Content-Type headers
  4. Look for common issues: trailing commas, unterminated strings, HTML responses

Can I parse partial JSON?

No. JSON.parse() requires valid complete JSON. There is no partial parsing mode. If you need to process incomplete data, consider streaming parsers.

Why does JSON.parse fail on valid-looking JSON?

Common hidden issues:

  • Invisible Unicode characters
  • BOM markers at file start
  • Mixed quote types (single vs double)
  • Invalid escape sequences

Use a hex editor or validator to find these invisible problems.

Is there a way to make JSON.parse more lenient?

No. JSON parsing is intentionally strict to ensure consistency across all platforms. If you need more flexibility, consider JSON5 (a superset that allows comments and trailing commas).

Conclusion

Unexpected token errors are frustrating but solvable. The key is systematic debugging:

  1. Print raw responses before parsing
  2. Validate externally with proper tools
  3. Check headers and status codes
  4. Handle errors gracefully

With practice, you will spot these issues quickly and fix them efficiently.

Remember: most JSON errors have nothing to do with the JSON itself. They come from server responses, encoding issues, or incorrect assumptions about the data format.

The best defense is prevention. Use JSON.stringify() instead of manual string building. Validate API responses before parsing. Add defensive error handling everywhere.

Your future self will thank you.


Stuck on a JSON error right now? Try our JSON Validator for instant feedback. It runs entirely in your browser, so your data stays private and secure.

Or use the JSON Formatter to beautify and validate in one step. Both tools help you fix JSON issues faster without sending your data anywhere.