254

What causes this error on the third line?

var products = [{
  "name": "Pizza",
  "price": "10",
  "quantity": "7"
}, {
  "name": "Cerveja",
  "price": "12",
  "quantity": "5"
}, {
  "name": "Hamburguer",
  "price": "10",
  "quantity": "2"
}, {
  "name": "Fraldas",
  "price": "6",
  "quantity": "2"
}];
console.log(products);
var b = JSON.parse(products); //unexpected token o

Open console to view error

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
coiso
  • 7,151
  • 12
  • 44
  • 63
  • 24
    You don't have any JSON? It's an array/object literal. – Bergi Jan 21 '13 at 03:41
  • Sidenote: I noticed that if you use JQuery and get a JSON string by the data-attribute e.g. `$('#mydata').data('person');` then JQuery turns the data string into a JSON object by itself. Here is no need to use `JSON.parse()`. – Avatar Jun 08 '23 at 11:05

24 Answers24

263

products is an object. (creating from an object literal)

JSON.parse() is used to convert a string containing JSON notation into a Javascript object.

Your code turns the object into a string (by calling .toString()) in order to try to parse it as JSON text.
The default .toString() returns "[object Object]", which is not valid JSON; hence the error.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 1
    is it not an Array? Why is it an object. Objects start with { and arrays start with [? or am i false here –  Sep 04 '16 at 17:20
  • 5
    Arrays are objects; that's what `.toString()` returns (as per the spec). – SLaks Sep 04 '16 at 18:01
  • 1
    Is the solution to stringify the object first? – Mohammed Noureldin Feb 03 '18 at 23:58
  • 11
    @MohammedNoureldin: No; the solution is to do nothing and use your object. – SLaks Feb 04 '18 at 00:19
  • 4
    What if I get my data from a remote service using Ajax, which gives me Json response back? And I want that response to be saved in JavaScript array object? – Mohammed Noureldin Feb 04 '18 at 00:54
  • 1
    @MohammedNoureldin: If you have an object, you don't need to parse it.. If you have string, you won't get an error. – SLaks Feb 04 '18 at 00:55
  • I don't really see how this is an answer to the question. – Enrico Nov 03 '20 at 16:00
  • 1
    @MohammedNoureldin To clarify, what you're asking is the opposite situation as the person asking this question. If what you received from the service is a JSON-encoded string, you should use `JSON.parse(theString)` to parse that string into whatever it represents (which may be an array, string, any valid JSON value). The person asking this question already has an object; there is no JSON in their situation so using `JSON` at all will not help them. – Mark Oct 16 '21 at 13:32
165

Let's say you know it's valid JSON, but you’re are still getting this...

In that case, it's likely that there are hidden/special characters in the string from whatever source your getting them. When you paste into a validator, they are lost - but in the string they are still there. Those characters, while invisible, will break JSON.parse().

If s is your raw JSON, then clean it up with:

// Preserve newlines, etc. - use valid JSON
s = s.replace(/\\n/g, "\\n")
               .replace(/\\'/g, "\\'")
               .replace(/\\"/g, '\\"')
               .replace(/\\&/g, "\\&")
               .replace(/\\r/g, "\\r")
               .replace(/\\t/g, "\\t")
               .replace(/\\b/g, "\\b")
               .replace(/\\f/g, "\\f");
// Remove non-printable and other non-valid JSON characters
s = s.replace(/[\u0000-\u0019]+/g,"");
var o = JSON.parse(s);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
EdH
  • 3,194
  • 3
  • 21
  • 23
  • 1
    Got a trailing special character after Base64 decoding, your method helped me a lot! Thx – Guillaume Jul 09 '16 at 23:24
  • don't trust a source responding with invalid JSON. Just inform them that the data is corrupt. they should fix it. if you try to "recover" the response like this or in similar ways, you'll be keeping an unstable communication. – Onur Yıldırım Jul 14 '16 at 18:34
  • Should be `s = s.replace(/[\u0000-\u001F]+/g,""); ` instead of `s = s.replace(/[\u0000-\u0019]+/g,""); `, for replacing all the control characters. Right? – HongchaoZhang Aug 17 '16 at 10:00
  • what is the logic behind `s.replace(/\\n/g, "\\n") ` I tested that, it applies to e.g. `"abc\\ndef".replace(/\\n/g,"\\'");` it'd turn it into `abc\'def` why do you want to do that? Does json not allow ending a line with a backslash.. can you comment a bit about what your examples do and why – barlop Oct 28 '16 at 16:44
  • Thanks, this really helps. Especially when you copy JSON to clipboard and there were hidden special endline characters in the console. – ChiHang Sep 25 '17 at 03:44
  • I have valid json `{"comment": "fixes\n"}` and I am trying to parse it `JSON.parse('{"comment": "fixes\n"}')` Console returns `SyntaxError: Unexpected token ` even though it is valid json. Could someone explain me why? – Pavol Travnik Oct 09 '19 at 14:38
81

It seems you want to stringify the object, not parse. So do this:

JSON.stringify(products);

The reason for the error is that JSON.parse() expects a String value and products is an Array.

Note: I think it attempts json.parse('[object Array]') which complains it didn't expect token o after [.

Onur Yıldırım
  • 32,327
  • 12
  • 84
  • 98
  • Worked for me. I stringified all array elements and array itself. Then json.parse() was successful. – cansu Aug 14 '20 at 07:54
  • Why would you do this though? It's already an object. Why stringify it only to parse it back to an object again? – Clonkex Aug 20 '21 at 07:17
  • @Clonkex to write it to a file, to post as text, to print on the document, to make a string search, to persist in a database, to debug, to make fun of it and a few other reasons... – Onur Yıldırım Aug 21 '21 at 05:07
  • My point is that you wouldn't `stringify` and then immediately `parse`. That would be pointless (unless you're trying to do a deep copy or something weird like that). Maybe you're saying to replace `parse` with `stringify`, but it sounds like you're saying to first `stringify` so that the `parse` works (which, as I say, would be pointless). – Clonkex Aug 22 '21 at 10:47
  • I don't know how you got "first stringify" from the answer but added "not parse" to be clear.. – Onur Yıldırım Aug 23 '21 at 04:54
35

JSON.parse is waiting for a String in parameter. You need to stringify your JSON object to solve the problem.

products = [{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}];
console.log(products);
var b = JSON.parse(JSON.stringify(products));  //solves the problem
Térence
  • 456
  • 4
  • 5
33

I found the same issue with JSON.parse(inputString).

In my case, the input string is coming from my server page (return of a page method).

I printed the typeof(inputString) - it was string, but still the error occurs.

I also tried JSON.stringify(inputString), but it did not help.

Later I found this to be an issue with the new line operator [\n], inside a field value.

I did a replace (with some other character, put the new line back after parse) and everything was working fine.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Derin
  • 1,202
  • 1
  • 15
  • 25
21

You should validate your JSON string here.

A valid JSON string must have double quotes around the keys:

JSON.parse({"u1":1000,"u2":1100})       // will be ok

If there are no quotes, it will cause an error:

JSON.parse({u1:1000,u2:1100})    
// error Uncaught SyntaxError: Unexpected token u in JSON at position 2

Using single quotes will also cause an error:

JSON.parse({'u1':1000,'u2':1100})    
// error Uncaught SyntaxError: Unexpected token ' in JSON at position 1
F1Krazy
  • 146
  • 1
  • 4
  • 14
hoogw
  • 4,982
  • 1
  • 37
  • 33
  • In my case, Grails 2.5.6 rendered `render ([key: value])` with single quotes, leading to the JSON parseError at position 1 in jquery Ajax. `render (groovy.json.JsonOutput.toJson ([key:value]))` helped me out. – philburns Oct 21 '19 at 10:10
14
products = [{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}];

change to

products = '[{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}]';
pktangyue
  • 8,326
  • 9
  • 48
  • 71
8

If there are leading or trailing spaces, it'll be invalid. Trailing and leading spaces can be removed as

mystring = mystring.replace(/^\s+|\s+$/g, "");

Source: JavaScript: trim leading or trailing spaces from a string

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
att
  • 617
  • 8
  • 17
3

Here's a function I made based on previous replies: it works on my machine but YMMV.

/**
   * @description Converts a string response to an array of objects.
   * @param {string} string - The string you want to convert.
   * @returns {array} - an array of objects.
  */
function stringToJson(input) {
  var result = [];

  // Replace leading and trailing [], if present
  input = input.replace(/^\[/, '');
  input = input.replace(/\]$/, '');

  // Change the delimiter to
  input = input.replace(/},{/g, '};;;{');

  // Preserve newlines, etc. - use valid JSON
  //https://stackoverflow.com/questions/14432165/uncaught-syntaxerror-unexpected-token-with-json-parse
  input = input.replace(/\\n/g, "\\n")
               .replace(/\\'/g, "\\'")
               .replace(/\\"/g, '\\"')
               .replace(/\\&/g, "\\&")
               .replace(/\\r/g, "\\r")
               .replace(/\\t/g, "\\t")
               .replace(/\\b/g, "\\b")
               .replace(/\\f/g, "\\f");

  // Remove non-printable and other non-valid JSON characters
  input = input.replace(/[\u0000-\u0019]+/g, "");

  input = input.split(';;;');

  input.forEach(function(element) {
    //console.log(JSON.stringify(element));

    result.push(JSON.parse(element));
  }, this);

  return result;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tmurphree
  • 79
  • 2
  • 11
2

One other gotcha that can result in "SyntaxError: Unexpected token" exception when calling JSON.parse() is using any of the following in the string values:

  1. New-line characters.

  2. Tabs (yes, tabs that you can produce with the Tab key!)

  3. Any stand-alone slash \ (but for some reason not /, at least not on Chrome.)

(For a full list see the String section here.)

For instance the following will get you this exception:

{
    "msg" : {
        "message": "It cannot
contain a new-line",
        "description": "Some discription with a     tabbed space is also bad",
        "value": "It cannot have 3\4 un-escaped"
    }
}

So it should be changed to:

{
    "msg" : {
        "message": "It cannot\ncontain a new-line",
        "description": "Some discription with a\t\ttabbed space",
        "value": "It cannot have 3\\4 un-escaped"
    }
}

Which, I should say, makes it quite unreadable in JSON-only format with larger amount of text.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
1

My issue was that I had commented HTML in a PHP callback function via Ajax that was parsing the comments and return invalid JSON.

Once I removed the commented HTML, all was good and the JSON was parsed without any issues.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chris
  • 31
  • 3
1

When you are using the POST or PUT method, make sure to stringify the body part.

I have documented an example here at https://gist.github.com/manju16832003/4a92a2be693a8fda7ca84b58b8fa7154

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Manjunath Reddy
  • 1,039
  • 2
  • 13
  • 22
1
[
  {
    "name": "Pizza",
    "price": "10",
    "quantity": "7"
  },
  {
    "name": "Cerveja",
    "price": "12",
    "quantity": "5"
  },
  {
    "name": "Hamburguer",
    "price": "10",
    "quantity": "2"
  },
  {
    "name": "Fraldas",
    "price": "6",
    "quantity": "2"
  }
]

Here is your perfect JSON content that you can parse.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
San
  • 27
  • 1
1

The only mistake is you are parsing an already-parsed object, so it's throwing an error. Use this and you will be good to go.

var products = [{
  "name": "Pizza",
  "price": "10",
  "quantity": "7"
}, {
  "name": "Cerveja",
  "price": "12",
  "quantity": "5"
}, {
  "name": "Hamburguer",
  "price": "10",
  "quantity": "2"
}, {
  "name": "Fraldas",
  "price": "6",
  "quantity": "2"
}];
console.log(products[0].name); // Name of item at 0th index

If you want to print the entire JSON content, use JSON.stringify().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kiran Maniya
  • 8,453
  • 9
  • 58
  • 81
0

products is an array which can be used directly:

var i, j;

for(i=0; i<products.length; i++)
  for(j in products[i])
    console.log("property name: " + j, "value: " + products[i][j]);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ic3b3rg
  • 14,629
  • 4
  • 30
  • 53
0

Now apparently \r, \b, \t, \f, etc. aren't the only problematic characters that can give you this error.

Note that some browsers may have additional requirements for the input of JSON.parse.

Run this test code in your browser:

var arr = [];
for(var x=0; x < 0xffff; ++x){
    try{
        JSON.parse(String.fromCharCode(0x22, x, 0x22));
    }catch(e){
        arr.push(x);
    }
}
console.log(arr);

Testing on Chrome, I see that it doesn't allow JSON.parse(String.fromCharCode(0x22, x, 0x22)); where x is 34, 92, or from 0 to 31.

Characters 34 and 92 are the " and \ characters respectively, and they are usually expected and properly escaped. It's characterss 0 to 31 that would give you problems.

To help with debugging, before you do JSON.parse(input), first verify that the input doesn't contain problematic characters:

function VerifyInput(input){
    for(var x=0; x<input.length; ++x){
        let c = input.charCodeAt(x);
        if(c >= 0 && c <= 31){
            throw 'problematic character found at position ' + x;
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pacerier
  • 86,231
  • 106
  • 366
  • 634
0

Oh man, solutions in all previous answers didn't work for me. I had a similar problem just now. I managed to solve it with wrapping with the quote. See the screenshot. Whoo.

Enter image description here

Original:

var products = [{
  "name": "Pizza",
  "price": "10",
  "quantity": "7"
}, {
  "name": "Cerveja",
  "price": "12",
  "quantity": "5"
}, {
  "name": "Hamburguer",
  "price": "10",
  "quantity": "2"
}, {
  "name": "Fraldas",
  "price": "6",
  "quantity": "2"
}];
console.log(products);
var b = JSON.parse(products); //unexpected token o
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Well Smith
  • 733
  • 7
  • 10
0

The error you are getting, i.e., "unexpected token o", is because JSON is expected, but an object is obtained while parsing. That "o" is the first letter of word "object".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shashank Bodkhe
  • 941
  • 10
  • 15
0

It can happen for a lot of reasons, but probably for an invalid character, so you can use JSON.stringify(obj); that will turn your object into a JSON, but remember that it is a jQuery expression.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

In my case there are the following character problems in my JSON string:

  1. \r
  2. \t
  3. \r\n
  4. \n
  5. :
  6. "

I have replaced them with other characters or symbols, and then reverted back again from coding.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Faraz Ahmed
  • 1,467
  • 2
  • 18
  • 33
0

This is now a JavaScript array of objects, not JSON format. To convert it into JSON format, you need to use a function called JSON.stringify().

JSON.stringify(products)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MD SHAYON
  • 7,001
  • 45
  • 38
-1

Why do you need JSON.parse? It's already in an array-of-object format.

Better use JSON.stringify as below:

var b = JSON.stringify(products);

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-1

The mistake I was doing was passing null (unknowingly) into JSON.parse().

So it threw Unexpected token n in JSON at position 0.

But this happens whenever you pass something which is not a JavaScript Object in JSON.parse().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aashutosh Rathi
  • 763
  • 2
  • 13
  • 28
-25

Use eval. It takes JavaScript expression/code as string and evaluates/executes it.

eval(inputString);
Jawa
  • 2,336
  • 6
  • 34
  • 39
  • 1
    Each invocation of eval() creates a new instance of the JavaScript interpreter. This can be a resource hog. – Yëco Mar 16 '15 at 18:05
  • This was the ONLY option that worked for me. Thanks – Rio Weber Nov 30 '20 at 17:32
  • 1
    usage of eval is highly discouraged, especially if you retrieve your data through an api, since it will leave you vulnrable to security issues and malicious attacks – Blueprint Jul 28 '21 at 12:33