If you see SyntaxError: Unexpected token 'o', "[object Obj"... is not valid JSON, the cause is always the same: you passed a JavaScript object directly to JSON.parse() instead of a JSON string.
Why the error says 'o' at position 1
JSON.parse() requires a string argument. When you pass something that is not a string, JavaScript calls .toString() on it before passing it to the parser. A plain JavaScript object has no custom toString(), so it inherits Object.prototype.toString, which returns the string "[object Object]".
Now JSON.parse("[object Object]") runs. The parser sees [ — a valid JSON array start — then immediately sees o, which is not a valid JSON value. Position 1 is the character right after the opening bracket.
const obj = { name: "Alice" };
// ❌ Wrong — obj.toString() = "[object Object]"
JSON.parse(obj);
// SyntaxError: Unexpected token 'o', "[object Obj"... is not valid JSON
// ✅ Correct — obj is already a JS object, use it directly
console.log(obj.name); // "Alice"
The three ways this error appears
1. Parsing an object that is already parsed
The most common case: you fetch data, response.json() already returns a JavaScript object, and then you mistakenly pass that object to JSON.parse() again.
// ❌ Double parse — response.json() already returns an object
const response = await fetch('/api/data');
const data = await response.json(); // data is now a JS object
const parsed = JSON.parse(data); // ❌ data is NOT a string
// ✅ Just use data directly
const parsed = data; // already a JS object
2. Parsing form input or state without stringifying first
const formData = {
username: document.getElementById('username').value,
age: parseInt(document.getElementById('age').value)
};
// ❌ formData is an object, not JSON
JSON.parse(formData);
// ✅ If you need a JSON string, stringify first
const jsonString = JSON.stringify(formData);
// ✅ Or just use formData directly — it's already an object
sendToServer(formData);
3. Passing state from a React/Vue component
// ❌ state is already an object
const [user, setUser] = useState({ name: "Alice" });
const parsed = JSON.parse(user); // SyntaxError
// ✅ If you need to deep-clone an object using JSON round-trip:
const clone = JSON.parse(JSON.stringify(user)); // ✅ stringify first, then parse
How to tell if something is already an object
const value = await response.json();
console.log(typeof value); // "object" — already parsed, do not call JSON.parse
console.log(typeof value === 'string'); // false
// Only call JSON.parse when the value is a string
if (typeof value === 'string') {
const parsed = JSON.parse(value);
} else {
// value is already a JS object/array — use it directly
}
When would you legitimately JSON.parse a string?
The correct input to JSON.parse() is always a string that contains valid JSON:
// ✅ Parsing JSON from localStorage (stored as string)
const stored = localStorage.getItem('user');
const user = JSON.parse(stored);
// ✅ Parsing a JSON string received from a WebSocket
socket.onmessage = (event) => {
const data = JSON.parse(event.data); // event.data is a string
};
// ✅ Parsing a hardcoded JSON string
const data = JSON.parse('{"name":"Alice","age":30}');
Validate the JSON string before parsing
If you are not sure whether a value is a valid JSON string, paste it into the JSON Validator to check before running JSON.parse() in your code. You can also use the JSON Formatter to inspect the structure.