Error HandlingIntermediate8 min49 / 63

try / except

Learn how to catch errors before they crash your program, handle different exception types gracefully, and always clean up after yourself.

Every program eventually runs into trouble. Maybe a user types letters when you expected a number. Maybe a file you need has been deleted. Maybe you divided by zero by accident.

When something goes wrong, Python raises an exception — a signal that says "I don't know how to continue." If you don't handle it, your program crashes.

The good news: Python gives you a way to catch those signals and decide what to do instead of crashing.

See it in action

Visual walkthrough1 / 6
1

Errors Happen — Don't Crash

When Python hits a problem it can't solve, it raises an exception and your program stops cold. Learning to catch exceptions means your program can recover instead of crashing.

Every exception has a name — like `ValueError` or `KeyError` — that tells you what went wrong.

#What Does a Crash Look Like?

Python stops immediately and prints an error message called a traceback.
number = int("hello")  # can't convert "hello" to a number

That red wall of text is called a traceback. It tells you what went wrong and where. The last line is the most important — it names the exception type (ValueError) and gives a short description.

Instead of letting Python crash, we can catch the exception ourselves.

#The try / except Block

Think of it like

Think of it like a safety net

Imagine a trapeze artist. The try block is the daring move. The except block is the safety net below. If the move goes perfectly, the net is never used. If something goes wrong, the net catches them — and the show goes on.

The program no longer crashes. We caught the ValueError and handled it.
try:
    number = int("hello")
except ValueError:
    print("That wasn't a valid number!")

Here is the basic structure:

  • try: — put the risky code here
  • except SomeError: — put the recovery code here, which runs only if that specific error happens

If no error occurs, the except block is completely skipped.

#Common Exception Types

Python has many built-in exception types. Here are the ones beginners encounter most often:

  • `ValueError` — right type, wrong value (e.g. int("hello"))
  • `TypeError` — wrong type entirely (e.g. "2" + 2)
  • `ZeroDivisionError` — dividing by zero
  • `KeyError` — looking up a dictionary key that doesn't exist
  • `IndexError` — accessing a list index that doesn't exist
  • `FileNotFoundError` — trying to open a file that isn't there
Catching a KeyError when a dictionary key doesn't exist.
scores = {"Alice": 95, "Bob": 87}

try:
    print(scores["Charlie"])
except KeyError:
    print("No score found for that name.")
Catching an IndexError when a list index doesn't exist.
numbers = [10, 20, 30]

try:
    print(numbers[99])
except IndexError:
    print("That index is out of range!")

#Catch Specific Exceptions — Not Everything

Common mistake

Avoid bare except — it hides real bugs

It is tempting to write except: with no error type to catch absolutely everything. Don't. A bare except will silence bugs you didn't intend to handle — like a typo in a variable name — making them nearly impossible to track down.

Always name the specific exception you expect, like except ValueError:.

Always be specific about which exception you're catching.
# BAD: catches everything, even bugs you didn't mean to handle
try:
    result = 10 / 0
except:
    print("Something went wrong")

# GOOD: only catches the specific error you expect
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

You can also catch multiple exception types in one except clause by grouping them in parentheses:

One except clause handles two different exception types.
def safe_divide(a, b):
    try:
        return a / b
    except (ZeroDivisionError, TypeError):
        print("Invalid input for division.")
        return None

print(safe_divide(10, 2))
print(safe_divide(10, 0))
print(safe_divide(10, "x"))

#Capturing the Error Message with "as e"

Sometimes you want to see the error message Python would have shown, but handle it gracefully. Use as e to capture the exception object — then you can print it or log it.

The variable e holds the exception object. Printing it shows the error message.
try:
    value = int("abc")
except ValueError as e:
    print("Caught an error:", e)
Tip

Log the error, don't silence it

In real programs, it is good practice to at least print or log the error message when you catch an exception. That way, if something unexpected happens, you have a clue about what went wrong instead of a mystery.

#else and finally

A try block can have two optional extra clauses:

  • `else:` runs only if the try block succeeded (no exception was raised)
  • `finally:` runs no matter what — whether an exception happened or not. It is perfect for cleanup like closing files.
else runs on success; finally always runs.
try:
    number = int(input("Enter a number: "))
except ValueError:
    print("That was not a number.")
else:
    print("Great! You entered:", number)
finally:
    print("Thanks for using the program!")
else only runs when there is no exception; finally runs in both cases.
# Simulating both paths
# --- Path 1: valid input ---
try:
    number = int("42")
except ValueError:
    print("Not a number.")
else:
    print("Success! Got:", number)
finally:
    print("Always runs.")

print("---")

# --- Path 2: invalid input ---
try:
    number = int("oops")
except ValueError:
    print("Not a number.")
else:
    print("Success! Got:", number)
finally:
    print("Always runs.")

#A Real-World Example

A function that gracefully handles a missing file and always reports when it is done.
def read_config(filename):
    try:
        file = open(filename)
    except FileNotFoundError:
        print(f"Config file '{filename}' not found. Using defaults.")
        return {}
    else:
        content = file.read()
        file.close()
        print("Config loaded successfully.")
        return content
    finally:
        print("read_config() finished.")

read_config("settings.txt")
Quick check

What is the purpose of the `finally` block in a try/except statement?

Key takeaways

  • Unhandled exceptions crash your program — use try/except to catch them gracefully.
  • Always catch specific exception types (like ValueError or KeyError), never use a bare except.
  • Use `as e` to capture and inspect the error message.
  • The `else` block runs only when no exception occurred; `finally` always runs — great for cleanup.
  • Knowing common exception names (ValueError, TypeError, KeyError, IndexError, ZeroDivisionError, FileNotFoundError) helps you write targeted handlers.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

What does this code print?

predict-output
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Oops, divided by zero!")
else:
    print("Division worked fine.")
finally:
    print("All done.")
Fix the bug#2

This code is meant to safely convert user input to an integer and print it, but it has a bug. What is wrong?

fix-bug
try:
    number = int("hello")
except:
    print("Please enter a valid number.")
print("You entered:", number)
Fill in the blank#3

Complete the code so it catches a KeyError when the name is not in the dictionary and prints 'Name not found.'

scores = {"Alice": 95, "Bob": 87}

try:
    print(scores["Charlie"])
except :
    print("Name not found.")
Reorder the lines#4

Put these lines in the right order to define a function that converts a string to an integer and returns 0 if it fails.

1
        return 0
2
    try:
3
        return int(value)
4
def safe_int(value):
5
    except ValueError:
Your turn
Practice exercise

Write a function called safe_int that takes a single argument and tries to convert it to an integer. If it succeeds, return the integer. If a ValueError occurs, print a friendly message and return 0. Test it with both a valid string like "42" and an invalid one like "banana".

Try it live — edit the code and hit Run to execute real Python:

solution.py · editable