Python Central HubSign in

Python Programming / Python Errors and Exceptions

try/except in Python

Handle runtime errors safely using try/except, multiple except blocks, and best practices.

What you'll learn

  • How try, except, else and finally fit together
  • How to catch specific exceptions and handle several types
  • How to use the exception object to report what went wrong
  • How to re-raise an exception and when to do it
  • The common mistakes that make error handling worse, not better

Why use try/except?

Exceptions are normal in real programs:

  • network failures
  • missing files
  • invalid user input

Instead of crashing, you can handle the problem and continue.

Basic try/except

Python
try:
    x = int(input("Enter a number: "))
    print(10 / x)
except Exception:
    print("Something went wrong")

This works, but it’s usually too broad.

Catch specific exceptions

Python
try:
    x = int(input("Enter a number: "))
    print(10 / x)
except ValueError:
    print("Please enter only digits.")
except ZeroDivisionError:
    print("Number can’t be 0.")

Catch multiple exception types

Python
try:
    x = int(input("Enter a number: "))
    print(10 / x)
except (ValueError, ZeroDivisionError) as e:
    print("Error:", e)

Capture the exception object

Python
try:
    int("abc")
except ValueError as e:
    print("Type:", type(e))
    print("Message:", e)

How Python picks an except block

When an exception is raised inside try, Python stops running the body right there. It then checks each except clause from top to bottom and runs the first one that matches. If none match, the exception keeps travelling up to the caller, and eventually ends the program with a traceback.

Because the first match wins, order matters. Put specific exceptions before general ones:

Python
try:
    items = [1, 2, 3]
    print(items[10])
except LookupError:
    print("caught by the general parent")
except IndexError:
    print("never reached")

IndexError is a child of LookupError, so the first clause always wins and the second is dead code. Swap them and the specific message runs.

The else block

else runs only when the try body finished without an exception. Use it to keep the try body small, so you only protect the line that can actually fail.

Python
def read_number(text):
    try:
        number = int(text)
    except ValueError:
        print("Not a number:", text)
        return None
    else:
        print("Parsed OK")
        return number
 
print(read_number("42"))
print(read_number("forty-two"))
Python
>>> read_number("42")
Parsed OK
42
>>> read_number("forty-two")
Not a number: forty-two

The finally block

finally runs every time: after success, after a handled error, even if the function returns early or an unhandled exception is flying past. It is the place for cleanup.

Python
def load(path):
    f = None
    try:
        f = open(path, encoding="utf-8")
        return f.read()
    except FileNotFoundError:
        print("File not found:", path)
        return ""
    finally:
        if f is not None:
            f.close()
            print("File closed")
 
print(load("missing.txt"))

For files, a with statement does the same cleanup in fewer lines. Reach for finally when you manage something that has no context manager.

Putting all four together

Python
def divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("Cannot divide by zero")
        result = None
    except TypeError as err:
        print("Bad operand types:", err)
        result = None
    else:
        print("Division succeeded")
    finally:
        print("divide() finished")
    return result
 
divide(10, 2)
divide(10, 0)
divide(10, "x")

Re-raising an exception

Sometimes you want to do something (log, clean up) but still let the error continue. A bare raise inside an except block re-raises the current exception with its original traceback.

Python
def parse_age(text):
    try:
        return int(text)
    except ValueError:
        print("Logging: invalid age received:", text)
        raise
 
try:
    parse_age("abc")
except ValueError as err:
    print("Caller handled:", err)

You can also translate one exception into another and keep the original as the cause with raise ... from ...:

Python
class ConfigError(Exception):
    pass
 
def load_port(value):
    try:
        return int(value)
    except ValueError as err:
        raise ConfigError("PORT must be a number") from err
 
try:
    load_port("eighty")
except ConfigError as err:
    print(err, "| caused by:", repr(err.__cause__))

Common mistakes

MistakeWhy it hurtsBetter
Bare except:Also catches KeyboardInterrupt and SystemExit, so Ctrl+C stops workingCatch a named exception
except Exception: passHides bugs completelyHandle it, log it or re-raise it
Huge try bodiesYou cannot tell which line failedWrap only the risky line
Wrong clause orderA general parent hides a specific childSpecific first, general last
Using exceptions for normal flowSlower and harder to readUse an if when a check is simple
Losing the traceback with raise err in a new placeConfusing debuggingUse bare raise
Python
# Bad: the typo is silently ignored
try:
    total = pricee * 2
except Exception:
    pass
 
# Better: only catch what you expect
prices = {"apple": 3}
try:
    total = prices["pear"] * 2
except KeyError:
    total = 0
print(total)

Best practices

  • Catch the narrowest exception you can.
  • Don’t silently ignore exceptions.
  • Log exceptions in production systems.
  • Avoid except Exception: unless you re-raise or report clearly.
  • Keep the try body short and move the success path into else.
  • Use finally or with for cleanup.

Visualize it

try / except / else / finally is a small decision tree. Python runs the try body; if an exception is raised it jumps to a matching except; the else runs only when no exception occurred; and finally always runs, error or not:

diagram try / except / else / finally mermaid
The except block runs only on an error, else only on success, and finally always runs.

Check what you learned

quizCheck yourself
  1. When does the else block of a try statement run?

    Show answer

    C — Only when the try body finished without raising an exception — else is the success path. It runs after the try body completes with no exception, and before finally.

  2. Why is a bare except: clause considered a mistake?

    Show answer

    B — It also catches KeyboardInterrupt and SystemExit, and hides bugs by treating every problem the same — A bare except catches everything, including exceptions meant to stop the program. Name the exceptions you expect.

  3. Inside an except block you want to log the problem and let it continue to the caller. What do you write?

    Show answer

    C — raise (with no arguments) — A bare raise re-raises the active exception and keeps its original traceback.

🧪 Try It Yourself

Exercise 1 – Catch a ValueError

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 2 – Multiple Except Blocks

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 3 – Raise a Custom Exception

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Was this page helpful?

Let us know how we did