I have below try-except to catch JSON parse errors:

with open(json_file) as j:try:json_config = json.load(j)except ValueError as e:raise Exception('Invalid json: {}'.format(e))

Why is During handling of the above exception, another exception occurred printed out, and how do I resolve it?

json.decoder.JSONDecodeError: Expecting ',' delimiter: line 103 column 9 (char 1093)During handling of the above exception, another exception occurred:Traceback (most recent call last):<....>raise Exception('Invalid json: {}'.format(e))Exception: Invalid json: Expecting ',' delimiter: line 103 column 9 (char 1093)
5

Best Answer


Currently, you are having an issue with raising the ValueError exception inside another caught exception. The reasoning for this solution doesn't make much sense to me, but if you change it.

raise Exception('Invalid json: {}'.format(e))

To

raise Exception('Invalid json: {}'.format(e)) from None

Making your end code.

with open(json_file) as j:try:json_config = json.load(j)except ValueError as e:raise Exception('Invalid json: {}'.format(e)) from None

You should get the desired result of catching an exception.

e.g.

>>> foo = {}>>> try:... var = foo['bar']... except KeyError:... raise KeyError('No key bar in dict foo') from None...Traceback (most recent call last):File "<stdin>", line 4, in <module>KeyError: 'No key bar in dict foo'

Sorry, I can't explain why this works precisely, but it seems to do the trick.

UPDATE:It looks like there's a PEP doc explaining how to suppress exceptions inside exception warnings.

During handling of the above exception, another exception occurred.

This unexpected event can disrupt the normal flow of a program or system, causing errors and potential issues.

When encountering such exceptions, it is crucial to have proper error handling and exception management in place to ensure the stability and reliability of the application.

By implementing robust error handling mechanisms, developers can effectively identify and address exceptions, preventing them from cascading and causing further problems.

Overall, handling exceptions is a fundamental aspect of software development that plays a vital role in maintaining the integrity and functionality of systems.

Since you're raising another exception from inside your except statement, python is just telling you that.

In other words, usually you use except to handle an exception and not make the program fail, but in this case you're raising another exception while already handling one, which is what python is telling you.

There is really nothing to be worried about, if that's the behavior you want. If you want to "get rid" of that message, you can perhaps write something to the output without raising another exception, or just make the first halt the program without using a try/except statement.


As Steven suggests, you can do:

raise Exception('Invalid json: {}'.format(e)) from e

to get both exceptions printed, like this:

Traceback (most recent call last):File "tmp.py", line 5, in <module>raise Exception('Invalid json: {}'.format(e)) from eExceptionThe above exception was the direct cause of the following exception:Traceback (most recent call last):<...>json.decoder.JSONDecodeError: Expecting ',' delimiter: line 103 column 9 (char 1093)

Or you can do this:

raise Exception('Invalid json: {}'.format(e)) from None

To suppress the first one and only log the Invalid json... exception.


By the way, doing something like raise Exception('Invalid json: {}'.format(e)) doesn't really make much sense, at that point you can just leave the original exception alone, since you're not adding much information to it.

Python is alerting you that you threw an exception while another one was in the process of being handled. The warning is there to alert you in case this was unexpected so that you know about the original exception. Consider a case like the following:

class Resource:def close(self):if cannot_close:raise Error("Cannot close")def write_data(self, data):...some_function():try:res = Resource()res.write_data("some data")except Error as e:res.close()

Let's say that write_data raises an exception, but then the close does so also, unexpectedly. When that happens, it's nice to know about both exceptions. In most cases, you want to know about the original exception raised by write_data but knowing about the one from close helps you know that something strange happened with close.

But for your case, you are simply restating the original error in a new way. Doing so lets you provide more context, for example:

with open(json_file) as j:try:json_config = json.load(j)except ValueError as e:raise Exception('Invalid json from file {}: {}'.format(json_file, e))

This would provide you with the path of the file that failed to be parsed as JSON, which is helpful context information that won't be in the original exception message.

So to tell Python that you are essentially re-raising the original exception, but with more context, you add from e.

with open(json_file) as j:try:json_config = json.load(j)except ValueError as e:raise Exception('Invalid json from file {}: {}'.format(json_file, e)) from e

This is equivalent to "exception chaining" in Java where you supply the original exception to the constructor of the new exception.

I have solved by using data.get(key) instead of data[key].