133

I am parsing json data. I don't have an issue with parsing and I am using simplejson module. But some api requests returns empty value. Here is my example:

{
"all" : {
    "count" : 0,
    "questions" : [     ]
    }
}

This is the segment of my code where I parse the json object:

 qByUser = byUsrUrlObj.read()
 qUserData = json.loads(qByUser).decode('utf-8')
 questionSubjs = qUserData["all"]["questions"]

As I mentioned for some requests I get the following error:

Traceback (most recent call last):
  File "YahooQueryData.py", line 164, in <module>
    qUserData = json.loads(qByUser)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/__init__.py", line 385, in loads
    return _default_decoder.decode(s)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/decoder.py", line 402, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/decoder.py", line 420, in raw_decode
    raise JSONDecodeError("No JSON object could be decoded", s, idx)
simplejson.decoder.JSONDecodeError: No JSON object could be decoded: line 1 column 0 (char 0)

What would be the best way to handle this error?

3
  • 5
    Actually, what is your question? Commented Dec 5, 2011 at 5:13
  • You answered the questions ;) Looks like I submit the question before really typing the question. Thanks for the answer. Commented Dec 5, 2011 at 6:07
  • 2
    Ok, I am glad I helped - it looks now like a telepathy ;) Thanks for including the question, though. Good luck! Commented Dec 5, 2011 at 8:21

2 Answers 2

240

There is a rule in Python programming called "it is Easier to Ask for Forgiveness than for Permission" (in short: EAFP). It means that you should catch exceptions instead of checking values for validity.

Thus, try the following:

try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except ValueError:  # includes simplejson.decoder.JSONDecodeError
    print('Decoding JSON has failed')

EDIT: Since simplejson.decoder.JSONDecodeError actually inherits from ValueError (proof here), I simplified the catch statement by just using ValueError.

Sign up to request clarification or add additional context in comments.

9 Comments

You should always catch the correct exception. Otherwise you might be missing a bug in the code if there is an actual ValueError exception, or some other exception which also inherits from ValueError.
@JulieinAustin: the problem is that in this case you really don't have much choice - stdlib's json module throws ValueError.
Then I'd stay away from that decoder. The original question was about the simplejson module and it very much does raise JSONDecodeError on bad input. See your earlier link.
@JulieinAustin: I would do otherwise, since it is actually... standard library. If you are not concerned about speed too much, I would use what is already available. Yes, simplejson does this in a more fine-grained way, but it has its own issues. What would you say if the try...except block would only encapsulate json.loads call? I think this would be better then, but would require some boiler place to meet the requirements (eg. changing class of the exception to something more fine-grained, but lets not try to save the world here).
ValueError is too broad to use in this context. In terms of user code qUserData["all"]["questions"] could throw ValueError too I believe. Let alone a ValueError being raised elsewhere inside simplejson. This is the kind of thing that could bite you really hard 6 months down the track when things start breaking for "no reason"
|
55

If you don't mind importing the json module, then the best way to handle it is through json.JSONDecodeError (or json.decoder.JSONDecodeError as they are the same) as using default errors like ValueError could catch also other exceptions not necessarily connected to the json decode one.

from json.decoder import JSONDecodeError


try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
    # do whatever you want

//EDIT (Oct 2020):

As @Jacob Lee noted in the comment, there could be the basic common TypeError raised when the JSON object is not a str, bytes, or bytearray. Your question is about JSONDecodeError, but still it is worth mentioning here as a note; to handle also this situation, but differentiate between different issues, the following could be used:

from json.decoder import JSONDecodeError


try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
    # do whatever you want
except TypeError as e:
    # do whatever you want in this case

3 Comments

Unfortunately, json.loads throws a TypeError when the JSON object isn't a str, bytes, or bytearray. This bit me recently because I had thought that JSONDecodeError handled those circumstances, e.g. when the argument to json.loads ends up being None.
@JacobLee: Thanks. The original question is about the best way to handle the JSONDecodeError so I have focused only on that one, but you're right and this case is definitely worth mentioning. I have added it into the answer.
You can also do import json at the beginning and then use except json.JSONDecodeError as e: in the exception handling.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.