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?
- Check the raw response (log it before parsing)
- Validate with external tools like JSON Validator
- Verify Content-Type headers
- 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:
- Print raw responses before parsing
- Validate externally with proper tools
- Check headers and status codes
- 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.