This Python Eats Exceptions

This Python eats Exceptions

Python like any other modern language has exception management. But I ran into an interesting edge case that stumped me quite a bit before I realized well python is different.

Let me explain with an example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Ex1(Exception):
    pass


class Ex2(Exception):
    pass


def afunction():
    try:
        print("Inside try block")
        raise Ex1()
    except Ex1:
        print("Exception caught in catch Block")
        raise Ex2()
    finally:
        print("In the finally block")
        return -1


afunction()

You would expect this to print

1
2
3
4
5
6
7
8
9
Inside try block
Exception caught in catch Block
In the finally block
Traceback (most recent call last):
  File "/Users/vivekv/projects/til/content/posts/exceptionbug.py", line 21, in <module>
    afunction()
  File "/Users/vivekv/projects/til/content/posts/exceptionbug.py", line 15, in afunction
    raise Ex2()
__main__.Ex2

ie the try, the catch the finally block and then the exception should bubble up to the top layer and since we are not handling it, it should fail.

But Surprise, surprise, we dont see the final exception. The output looks like

Inside try block
Exception caught in catch Block
In the finally block

So the Ex2 which was supposed to bubble up was swallowed by Python. I tried running it under both Python 3.9.5 and Python 2.7.17 and the results are the same. So I went spelunking into the python documentation and found something very interesting.

If the finally clause executes a break, continue or return statement, exceptions are not re-raised.

So that small return -1 made the difference. Once I removed it, the code behaved as expected.

That is python for you. So be careful what you do in your finally clause especially when you are returning values, any exception that you throw in your except blocks will be swallowed!

I decided to try this out in Java, the tried and trusted enterprise powerhouse language.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Ex1 extends Exception
{
}

class Ex2 extends Exception
{
}


class ExceptionBug
{
	public static void main (String[] args) throws Exception
	{
        somefunc();
    }

    static int somefunc()
    {
		try
		{
			System.out.println("Inside try block");
            throw new Ex1();
		}
		catch(Ex1 ex)
		{
			System.out.println("Exception caught in Catch block");
            throw new Ex2();
		}
        finally {
            // rest program will be executed
            System.out.println("In the finally block");
            return -1;
	    }
    }
}

And Java shows the exact same behavior as Python. This program runs with the following output

1
2
3
4
$ java -cp . ExceptionBug
Inside try block
Exception caught in Catch block
In the finally block

Removing the return statement in the finally block brings out the same behavior as python. So I guess learned an important lesson -

finally {} blocks is not a great place to return a value because they could potentially supress the exceptions being raised within the exception blocks.

Yes I realise the title is misleading it is not just python but Java too is eating exceptions. I found this behavior in Python code so that is the reason wrote the title but I realised when I was researching this idea, Java too had the same behavior.

updatedupdated2021-07-182021-07-18