291

I've been trying to figure out a good way to load JSON objects in Python. I send this json data:

{'http://example.org/about': {'http://purl.org/dc/terms/title': [{'type': 'literal', 'value': "Anna's Homepage"}]}}

to the backend where it will be received as a string then I used json.loads(data) to parse it.

But each time I got the same exception :

ValueError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

I googled it but nothing seems to work besides this solution json.loads(json.dumps(data)) which personally seems for me not that efficient since it accept any kind of data even the ones that are not in json format.

Any suggestions will be much appreciated.

linusg
  • 6,289
  • 4
  • 28
  • 78
raeX
  • 3,197
  • 2
  • 14
  • 21
  • 79
    My mistake was not double quote thing. I was adding a comma after the last key-value pair like we do in python. You don't do that in JSON. – Luv33preet Jul 05 '18 at 09:43
  • 14
    **always** use `json.dumps()` rather than just writing out python and hoping that the python notation will work in your JavaScript reader. – vy32 Mar 12 '19 at 19:21
  • I had this problem because I took the result of a `print(jsonpickle_deserialized_object_string)` and tried to use it. For some reason `print()` changes the quotes from `"` to `'` – StingyJack Dec 15 '19 at 16:25
  • @Luv33preet, thanks, got it solved. but I expecting logger-msg as missing-comma or something, but this error doesn't tells anything about it, – GD- Ganesh Deshmukh Mar 28 '20 at 13:48
  • see https://stackoverflow.com/a/63862387/1497139 for a quick fix – Wolfgang Fahl Sep 12 '20 at 19:50
  • 1
    My mistake was leaving some `//` javascript comments in the JSON that was posting to the server, that is not valid JSON. – teewuane Jun 15 '21 at 18:20
  • This might save someone's time. In my case, I was sending a Postman request with an undefined variable. This happened to me after migrating my collections from a team's workspace to my personal workspace, omitting to export the relevant environment. After setting up the Postman's variables, the request was being parsed well. – thanos.a Jan 17 '22 at 09:56
  • Using the `hjson` module as mentioned in [this excellent answer](https://stackoverflow.com/a/34812991/9282844) solved the problem for me. – Guimoute Jun 16 '23 at 21:39

31 Answers31

308

This:

{
    'http://example.org/about': {
        'http://purl.org/dc/terms/title': [
            {'type': 'literal', 'value': "Anna's Homepage"}
        ]
     }
}

is not JSON.
This:

{
     "http://example.org/about": {
         "http://purl.org/dc/terms/title": [
             {"type": "literal", "value": "Anna's Homepage"}
          ]
      }
}

is JSON.

EDIT:
Some commenters suggested that the above is not enough.
JSON specification - RFC7159 states that a string begins and ends with quotation mark. That is ".
Single quoute ' has no semantic meaning in JSON and is allowed only inside a string.

Community
  • 1
  • 1
ElmoVanKielmo
  • 10,907
  • 2
  • 32
  • 46
  • 7
    Thanx :) I didnt pay attention to that , I am using the correct json format when sending the data but when it is received at the backend the double quotes is replaced by single ones ! therefore i got that exception. – raeX Sep 14 '16 at 13:32
  • 271
    this is not a solution. A solution would tell him how to modify the string to valid json. – FistOfFury Jan 23 '20 at 15:00
  • 8
    @FistOfFury I'm sorry but your statement is based on a false assumption that arbitrary invalid JSON string can be reliably turned programmatically into a valid one. Lots of answers for this question try to tackle the problem by replacing ' with " and so on. Do I have to give you simple examples of input strings which will break these "solutions"? Apparently OP understood that what we are dealing with is not JSON and was able to proceed - accepted my answer. Hint - the input string looks more like output of Python dict.__repr__() method. – ElmoVanKielmo Jan 24 '20 at 08:43
  • 39
    @ElmoVanKielmo doesn't change the fact that your answer is a statement, not an answer to the question. You provide no context or explanation. People coming here looking for information about the question will be disappointed. You may have helped OP, but others not so much. – FistOfFury Apr 09 '20 at 02:25
  • 6
    A simple clear statement often helps a lot. Specially, when there are plenty of other answers around. – bomben Aug 28 '20 at 12:18
  • Downvoted, this isn't helpful. Many times we won't have control over the upstream source of data but we still need to work with it. "This isn't valid JSON" doesn't help solve the problem. – zfj3ub94rf576hc4eegm Jun 18 '21 at 18:51
  • @zfj3ub94rf576hc4eegm many times we deal with data which is not in the format we expect. The issue here is that one thinks they're dealing with JSON. Name it. It;s not JSON. It's another data format. You can deal with it but don't call it JSON when it's not. – ElmoVanKielmo Jun 19 '21 at 23:06
  • No, the issue is that we have data we need to deal with and it doesn't matter what you call it. Identifying the fact that it's not JSON doesn't solve the problem. Imagine telling your manager you "solved the problem" by figuring out that your data source wasn't JSON. – zfj3ub94rf576hc4eegm Jun 21 '21 at 04:14
  • @zfj3ub94rf576hc4eegm for god's sake. Specification of the data format exposed by the API is part of the contract and is essential in stable systems. Imagine telling your manager that you provided JSON API which doesn't produce JSON... The issue OP had was not a coding challenge to convert guessed format into JSON. Either the documentation was erroneously stating that the output format is JSON or the documentation was not read. So either you open an issue for the data provider or you use the API as documented. – ElmoVanKielmo Jun 21 '21 at 10:29
  • There are plenty of managers who don't even know what JSON is. Even for the ones that do know, telling them it's malformed doesn't solve the problem. Ultimately what matters is whether you can muster something useful out of the upstream data and to that end this answer provides nothing in the way of helpful information. – zfj3ub94rf576hc4eegm Jun 21 '21 at 16:49
  • @zfj3ub94rf576hc4eegm I report a bug to the owner of the faulty data source stating that I was supposed to get JSON. I report to my manager that I reported the bug and I do other tasks. Not only the bug is fixed in a reasonable time but my time is saved and there's more progress overall. Nobody pays us for fixing 3rd party bugs. I also mentioned how important reading the docs is. Well, not only docs. If you read the question carefuly, you would know that OP was creating faulty data on the frontend. Working it around on backend wasn't a good idea. Solution was to send valid JSON to backend. – ElmoVanKielmo Jun 21 '21 at 18:30
  • 1
    Very helpful when put this simply! – Kraken Oct 30 '22 at 08:04
155

as JSON only allows enclosing strings with double quotes you can manipulate the string like this:

s = s.replace("\'", "\"")

if your JSON holds escaped single-quotes (\') then you should use the more precise following code:

import re
p = re.compile('(?<!\\\\)\'')
s = p.sub('\"', s)

This will replace all occurrences of single quote with double quote in the JSON string s and in the latter case will not replace escaped single-quotes.

You can also use js-beautify which is less strict:

$ pip install jsbeautifier
$ js-beautify file.js
elig
  • 2,635
  • 3
  • 14
  • 24
  • 20
    Not a good idea because it can replace all 's to "s which is wrong: EXAMPLE: 'it's bad' -> "it"s bad" -> malformed string – Reihan_amn Feb 25 '20 at 00:35
  • 3
    @Reihan_amn I've added a more precise regex alternative for cases where escaped single-quotes are utilized. – elig Sep 02 '20 at 00:30
  • 1
    thx I am using https://stackoverflow.com/a/63862387/1497139 instead now – Wolfgang Fahl Sep 12 '20 at 19:49
  • I added a test case testSingleQuoteToDoubleQuoteStackoverflow to https://github.com/WolfgangFahl/pyLoDStorage/blob/master/tests/testJson.py per the discussion in https://stackoverflow.com/a/63862387/1497139 it shows the difference in results: {'cities': [{'name': "Upper Hell's Gate"}, {'name': "N'zeto"}] {"cities": [{"name": "Upper Hell's Gate"}, {"name": "N'zeto"}] {"cities": [{"name": "Upper Hell"s Gate"}, {"name": "N"zeto"}] – Wolfgang Fahl Sep 13 '20 at 05:56
  • {'name': "Lubov' Mal'ceva", 'url': 'https://vk.com/id283041382', 'id': 'id283041382'} {'url': 'https://vk.com/id459518460', 'id': 'id459518460', 'name': "Pid'z Achill"} {'url': 'https://vk.com/id107236823', 'id': 'id107236823', 'name': "Ksenia Anatol'evna"} {'url': 'https://vk.com/id513742225', 'id': 'id513742225', 'name': "Saida'lo Kamolov"} – pavlovma007 Nov 13 '20 at 15:47
  • @pavlovma007 please provide full code and error messages – elig Dec 14 '20 at 02:24
  • Please do not overwrite python commands (like `str = p.sub('\"', str)`, above). `str` is an awful variable name. `_str` is fine or whatever else you want. – Mike Pennington Sep 30 '22 at 17:56
123
import ast

inpt = {'http://example.org/about': {'http://purl.org/dc/terms/title':
                                     [{'type': 'literal', 'value': "Anna's Homepage"}]}}

json_data = ast.literal_eval(json.dumps(inpt))

print(json_data)

this will solve the problem.

balaji k
  • 1,231
  • 1
  • 5
  • 5
63

In my case, double quotes was not a problem.

Last comma gave me same error message.

{'a':{'b':c,}}
           ^

To remove this comma, I wrote some simple code.

import json

with open('a.json','r') as f:
    s = f.read()
    s = s.replace('\t','')
    s = s.replace('\n','')
    s = s.replace(',}','}')
    s = s.replace(',]',']')
    data = json.loads(s)

And this worked for me.

greentec
  • 2,130
  • 1
  • 19
  • 16
  • 4
    +1 I can confirm this. The trailing comma does produce this error message. Example: `echo '{"json":"obj",}' | python -m json.tool` , when run in the shell, gives "Expecting property name enclosed in double quotes: line 1 column 15 (char 14)". Trailing commata are not legal JSON, but it would be nice if the Python JSON module emitted a relevant error message in this case. – András Aszódi May 07 '20 at 13:27
  • 1
    Yes this thread helped me. I was also getting this error because of a comma in the end. Thank you – Sandeep Jul 14 '22 at 16:26
  • Is there a way to _keep_ the comma (for simplicity of adding another key-value pairs) and get rid of the error? – Ashark May 23 '23 at 10:50
45

Solution 1 (Very Risky)

You can simply use python eval function.

parsed_json = eval(your_json)

Solution 2 (No Risk)

You can use ast library which is included in python by default, it also safely evaluate the expression.

import ast

parsed_json = ast.literal_eval(your_json)
Ujjwal Agrawal
  • 830
  • 1
  • 8
  • 14
  • 4
    Or even `ast.literal_eval` to "Safely evaluate an expression node or a string containing a Python expression." – Drakes Jul 28 '21 at 06:28
  • The "very risky" method finally work to convert the data from a file into a python dict. Thanks! – Alex Jul 20 '23 at 09:51
9

Quite simply, that string is not valid JSON. As the error says, JSON documents need to use double quotes.

You need to fix the source of the data.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
9

I've checked your JSON data

{'http://example.org/about': {'http://purl.org/dc/terms/title': [{'type': 'literal', 'value': "Anna's Homepage"}]}}

in http://jsonlint.com/ and the results were:

Error: Parse error on line 1:
{   'http://example.org/
--^
Expecting 'STRING', '}', got 'undefined'

modifying it to the following string solve the JSON error:

{
    "http://example.org/about": {
        "http://purl.org/dc/terms/title": [{
            "type": "literal",
            "value": "Anna's Homepage"
        }]
    }
}
Yaron
  • 10,166
  • 9
  • 45
  • 65
7

JSON strings must use double quotes. The JSON python library enforces this so you are unable to load your string. Your data needs to look like this:

{"http://example.org/about": {"http://purl.org/dc/terms/title": [{"type": "literal", "value": "Anna's Homepage"}]}}

If that's not something you can do, you could use ast.literal_eval() instead of json.loads()

alexbclay
  • 1,389
  • 14
  • 19
  • 3
    That is not a restriction of the Python library, but of the JSON format itself. – Daniel Roseman Sep 14 '16 at 13:22
  • You are correct. However, some JSON parsers do not enforce the double quotes. I'll update my answer. – alexbclay Sep 14 '16 at 13:24
  • provided this not-JSON never has any double quotes inside single-quoted strings, all you have to do is string-substitute all singles to doubles before invoking `json.loads()` – nigel222 Sep 14 '16 at 14:26
  • 2
    Using `ast.literal_eval` will result in `ValueError: malformed string` if the JSON string has a boolean value. – Scratch'N'Purr Nov 27 '18 at 13:55
  • @Scratch'N'Purr is this still the case? I had the same exact issue as the OP where I had to load JSON that was printed to stdout, and fixed with literal_eval(). I put an extra k/v into the string where the v was a False value (after reading your comment). To my surprise, literal_eval() was still able to load it just fine. –  Mar 06 '21 at 21:47
  • 1
    @JeffSpicoli yes, json booleans are true/false, note the lowercase t/f. – Scratch'N'Purr Mar 07 '21 at 13:19
  • Oh good point... had forgotten and was thinking capital T/F like in Python (but is lower case in JSON) –  Mar 08 '21 at 00:25
7

If you want to convert a json string with single quotes to python dict use ast.literaleval()

>>> import ast
>>> payload = "{'hello': 'world'}"
>>> ast.literal_eval(payload)
{'hello': 'world'}
>>> type(ast.literal_eval(payload))
<class 'dict'>

This will convert the payload to a python dict.

Akash Ranjan
  • 922
  • 12
  • 24
5
x = x.replace("'", '"')
j = json.loads(x)

Although this is the correct solution, but it may lead to quite a headache if there a JSON like this -

{'status': 'success', 'data': {'equity': {'enabled': True, 'net': 66706.14510000008, 'available': {'adhoc_margin': 0, 'cash': 1277252.56, 'opening_balance': 1277252.56, 'live_balance': 66706.14510000008, 'collateral': 249823.93, 'intraday_payin': 15000}, 'utilised': {'debits': 1475370.3449, 'exposure': 607729.3129, 'm2m_realised': 0, 'm2m_unrealised': -9033, 'option_premium': 0, 'payout': 0, 'span': 858608.032, 'holding_sales': 0, 'turnover': 0, 'liquid_collateral': 0, 'stock_collateral': 249823.93}}, 'commodity': {'enabled': True, 'net': 0, 'available': {'adhoc_margin': 0, 'cash': 0, 'opening_balance': 0, 'live_balance': 0, 'collateral': 0, 'intraday_payin': 0}, 'utilised': {'debits': 0, 'exposure': 0, 'm2m_realised': 0, 'm2m_unrealised': 0, 'option_premium': 0, 'payout': 0, 'span': 0, 'holding_sales': 0, 'turnover': 0, 'liquid_collateral': 0, 'stock_collateral': 0}}}}

Noticed that "True" value? Use this to make things are double checked for Booleans. This will cover those cases -

x = x.replace("'", '"').replace("True", '"True"').replace("False", '"False"').replace("null", '"null"')
j = json.loads(x)

Also, make sure you do not make

x = json.loads(x)

It has to be another variable.

Amit Ghosh
  • 1,500
  • 13
  • 18
3

I used this method and managed to get the desired output. my script

x = "{'inner-temperature': 31.73, 'outer-temperature': 28.38, 'keys-value': 0}"

x = x.replace("'", '"')
j = json.loads(x)
print(j['keys-value'])

output

>>> 0
Hamed
  • 1,166
  • 8
  • 10
3

You can use the json5 package https://pypi.org/project/json5/ instead of json package. This package can deal with single quotes. The decoding function is json5.loads(data) and similar to the json package.

Tobias Senst
  • 2,665
  • 17
  • 38
2

As it clearly says in error, names should be enclosed in double quotes instead of single quotes. The string you pass is just not a valid JSON. It should look like

{"http://example.org/about": {"http://purl.org/dc/terms/title": [{"type": "literal", "value": "Anna's Homepage"}]}}
Pavel Gurkov
  • 737
  • 5
  • 14
2
with open('input.json','r') as f:
    s = f.read()
    s = s.replace('\'','\"')
    data = json.loads(s)

This worked perfectly well for me. Thanks.

rohit9786
  • 21
  • 1
2

The below code snippet will help to transform data into JSON. All single-quotes should be converted into double-quotes to jsonify the data.

data = {
"http://example.org/about": {
    "http://purl.org/dc/terms/title": [{
        "type": "literal",
        "value": "Anna's Homepage"
    }]
}}
parsed_data = data.replace("'", '"')
data_json = json.loads(parsed_data)
Muhammad Tahir
  • 434
  • 1
  • 6
  • 7
1

I had similar problem . Two components communicating with each other was using a queue .

First component was not doing json.dumps before putting message to queue. So the JSON string generated by receiving component was in single quotes. This was causing error

 Expecting property name enclosed in double quotes

Adding json.dumps started creating correctly formatted JSON & solved issue.

Rahul Bagal
  • 220
  • 3
  • 7
1

As the other answers explain well the error occurs because of invalid quote characters passed to the json module.

In my case I continued to get the ValueError even after replacing ' with " in my string. What I finally realized was that some quote-like unicode symbols had found their way into my string:

 “  ”  ‛  ’  ‘  `  ´  ″  ′ 

To clean all of these you can just pass your string through a regular expression:

import re

raw_string = '{“key”:“value”}'

parsed_string = re.sub(r"[“|”|‛|’|‘|`|´|″|′|']", '"', my_string)

json_object = json.loads(parsed_string)

1

For anyone who wants a quick-fix, this simply replaces all single quotes with double quotes:

import json 

predictions = []

def get_top_k_predictions(predictions_path):
    '''load the predictions'''
    
    with open (predictions_path) as json_lines_file:
        for line in json_lines_file:
            predictions.append(json.loads(line.replace("'", "\"")))
            
    
get_top_k_predictions("/sh/sh-experiments/outputs/john/baseline_1000/test_predictions.jsonl")
information_interchange
  • 2,538
  • 6
  • 31
  • 49
1

If you are having a problem transform the dict to string and with double quote, this can help:

json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')

json.loads documentation

elan lima
  • 1,105
  • 6
  • 6
1

The json syntax requires quotation marks for each "key" and "value". This makes it such a robust data format. In the following example I'm using colors and color as a key:

{"colors":[
  {
     "color":"red",
     "value":"#f00"
  },
  {
     "color":"green",
     "value":"#0f0"
  },
  {
     "color":"blue",
     "value":"#00f"
  },
  {
     "color":"cyan",
     "value":"#0ff"
  },
  {
     "color":"magenta",
     "value":"#f0f"
  },
  {
     "color":"yellow",
     "value":"#ff0"
  },
  {
     "color":"black",
     "value":"#000"
  }]}
chrisurf
  • 31
  • 3
1

I would highly recommend usage of json prettify tools like JSON Prettifier for the same as it helped me fix the error of a trailing comma that I had in the JSON file, which yielded the same error.

rohetoric
  • 347
  • 3
  • 11
0

I had the same problem and what I did is to replace the single quotes with the double one, but what was worse is the fact I had the same error when I had a comma for the last attribute of the json object. So I used regex in python to replace it before using the json.loads() function. (Be careful about the s at the end of "loads")

import re

with open("file.json", 'r') as f:
     s = f.read()
     correct_format = re.sub(", *\n *}", "}", s)
     data_json = json.loads(correct_format)

The used regex return each comma followed by a newline and "}", replacing it just with a "}".

0

I've had this error trying to normalize nested JSON column in Pandas. As noted by @Reihan_amn, replacing all single quotes with double quotes may affect the actual content. Therefore, when getting this error, you should replace only the ' that are where " should be in JSON syntax. You can do it with the following regular expression:

import re
import json

invalid_json = """{'http://example.org/about': {'http://purl.org/dc/terms/title': [{'type': 'literal', 'value': "Anna's Homepage"}]}}"""

valid_json = re.sub( "(?<={)\'|\'(?=})|(?<=\[)\'|\'(?=\])|\'(?=:)|(?<=: )\'|\'(?=,)|(?<=, )\'", "\"", invalid_json)

print(json.loads(valid_json))

This would suffice if the only problem was that there were single quotes (') in places were double quotes (") should be, in your original misformatted JSON document. But you would still get an error, if there are double quotes somewhere in your document that are also not part of JSON syntax. In this case I would suggest a 4 step-solution:

  1. Replace all double quotes that are part of JSON syntax with single quotes (with the regex like above but ' and " swapped).

  2. Replace all (leftover) double quotes with some special character that does not feature in your document, e.g. ``. You can do it with re.sub("\"", "``", x).

  3. Replace all single quotes that are where the double quotes in JSON should be, with double quotes, using the regex given above.

You may now load JSON document and read it into a Pandas DataFrame with pd.json_normalize(df["json_col"].apply(json.loads)).

  1. If you want, you can replace back all `` (or a special character of your choice) with ".
m7s
  • 103
  • 1
  • 6
0

My problem was that I copy and pasted a JSON snippet and the double quotes that were used were somehow a different, unrecognized double quote character. My file was valid JSON after replacing the double quotes.

Pigpocket
  • 449
  • 5
  • 24
0

Its easy for example

import json

my_str = '{"message_type": "fixed_price_difference", "message": "Hello hello"}'

print(type(json.loads(my_str)), json.dumps(my_str))

Output:
    <class 'dict'> "{\"message_type\": \"fixed_price_difference\", \"message\": \"Hello hello\"}"

Syntax is very important for example

Bad syntax and not correct: my_str = "{'message_type': 'fixed_price_difference', 'message': 'Hello hello"}'

Correct syntax: my_str = '{"message_type": "fixed_price_difference", "message": "Hello hello"}'

Finally: States that a string begins and ends with quotation mark.

Muhammadalive
  • 648
  • 5
  • 5
0

Since your string is a valid JavaScript object, you could use the Js2Py library:

import js2py

content = """x = {'http://example.org/about': {'http://purl.org/dc/terms/title': [{'type': 'literal', 'value': "Anna's Homepage"}]}}"""
content = js2py.eval_js(content)

print(content.to_dict())
Tim Nieradzik
  • 112
  • 1
  • 6
0

in my case, error is not in json.loads(data)

I had done some errors with json structure before, so there was a shortage of part in it, such as

{'http://example.org/about': {'http://purl.org/dc/terms/title':

this is also a case which raises this error

lam vu Nguyen
  • 433
  • 4
  • 9
0

You input seems to be a valid (Amazon) ion although not json. In that case, you should be able to parse it as ion, and then output it as json.

single_quote_json = {'http://example.org/about': {'http://purl.org/dc/terms/title': [{'type': 'literal', 'value': "Anna's Homepage"}]}}
    
import amazon.ion.simpleion as ion
from amazon.ion.json_encoder import IonToJSONEncoder
import json

parsed_ion = ion.loads(str(single_quote_json))
json.dumps(parsed_ion, cls=IonToJSONEncoder)

Output:

'{"http://example.org/about": {"http://purl.org/dc/terms/title": [{"type": "literal", "value": "Anna\'s Homepage"}]}}'

Ref: Documentation on Amazon Ion: https://amzn.github.io/ion-docs/guides/cookbook.html#down-converting-to-json

learnerer
  • 396
  • 1
  • 2
  • 17
-1

Use the eval function.

It takes care of the discrepancy between single and double quotes.

msamogh
  • 147
  • 8
-2

I have run into this problem multiple times when the JSON has been edited by hand. If someone was to delete something from the file without noticing it can throw the same error.

For instance, If your JSON last "}" is missing it will throw the same error.

So If you edit you file by hand make sure you format it like it is expected by the JSON decoder, otherwise you will run into the same problem.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Sneil
  • 134
  • 2
  • 11
-3

It is always ideal to use the json.dumps() method. To get rid of this error, I used the following code

json.dumps(YOUR_DICT_STRING).replace("'", '"')
Michael Elimu
  • 61
  • 2
  • 7