This rule raises an issue when an except statement has had all its exceptions caught by a previous except clause.

Why is this an issue?

Exceptions handlers (except) are evaluated in the order they are written. Once a match is found, the evaluation stops.

In some contexts, an except block is dead code as it will never catch any exception:

How to fix it

When using multiple except statements, make sure to:

Code examples

Noncompliant code example

def foo():
    try:
        raise FloatingPointError()
    except (ArithmeticError, RuntimeError) as e:
        print(e)
    except FloatingPointError as e: # Noncompliant: FloatingPointError is a subclass of ArithmeticError.
        print("Never executed")
    except OverflowError as e: # Noncompliant: OverflowError is a subclass of ArithmeticError.
        print("Never executed")

    try:
        raise TypeError()
    except TypeError as e:
        print(e)
    except TypeError as e: # Noncompliant: duplicate except.
        print("Never executed")

    try:
        raise ValueError()
    except BaseException as e:
        print(e)
    except: # Noncompliant: this is equivalent to "except BaseException" block.
        print("Never executed")

Compliant solution

def foo():
    try:
        raise FloatingPointError()
    except FloatingPointError as e:
        print("Executed")
    except OverflowError as e:
        print("Executed")
    except (ArithmeticError, RuntimeError) as e:
        print(e)

    try:
        raise TypeError()
    except TypeError as e:
        print(e)

    try:
        raise ValueError()
    except BaseException as e:
        print(e)

Note: It is generally not recommended to try catching BaseException, as it is the base class for all built-in exceptions in Python, including system-exiting exceptions like SystemExit or KeyboardInterrupt, which are typically not meant to be caught. See PEP 352 for more information.

Resources

Documentation