🛡️
Coding🎓 Ages 14-18Intermediate 13 min read

Python Error Handling (try/except)

Learn Python error handling with try and except: catch exceptions, handle specific error types, validate user input, and use else and finally. Write robust programs with runnable code, a worked example and a quiz.

Key takeaways

  • An exception is a runtime error that stops a program unless you handle it
  • Code that might fail goes in a try block; the response goes in an except block
  • Catch specific exception types like ValueError or ZeroDivisionError, not just any error
  • try/except is ideal for validating user input without crashing
  • else runs when no error happened, and finally always runs for cleanup

When good programs go wrong

Even perfectly written code can run into trouble. A user types "ten" when you asked for a number. A file you tried to open isn't there. You divide by a value that turns out to be zero. When something like this happens, Python raises an exception — a special signal that something went wrong. If you do nothing, that exception crashes your program with a wall of red text. Error handling is how you stay in control: you catch the problem, respond sensibly, and keep running.

If you're comfortable with conditionals and functions, you're ready to make your programs robust.

What an exception looks like

Let's see a program crash on purpose:

number = int("hello")
print("This line never runs")

int("hello") can't turn the word "hello" into a number, so Python raises a ValueError and stops immediately. You'll see a traceback ending with:

ValueError: invalid literal for int() with base 10: 'hello'

The crucial detail: the second line never runs. An unhandled exception halts everything that follows.

The try and except blocks

To handle an exception, wrap the risky code in a try block and describe your response in an except block:

try:
    number = int("hello")
    print("Converted successfully")
except ValueError:
    print("That wasn't a valid number.")

print("The program keeps going.")

Reading it line by line:

  • The try: block holds the code that might fail.
  • int("hello") raises a ValueError, so Python skips the rest of the try block (the success message never prints) and jumps to the matching except.
  • except ValueError: catches that specific error and runs its body, printing a friendly message.
  • Because the exception was handled, the program doesn't crash — the final line still runs, printing The program keeps going.

That's the whole idea: try the risky thing, and if it fails, respond instead of crashing.

Catch specific exceptions

Different problems raise different exception types. Two of the most common:

  • ValueError — a value is the wrong kind, like int("hello").
  • ZeroDivisionError — you divided by zero.
try:
    a = int("8")
    b = int("0")
    print(a / b)
except ValueError:
    print("Please enter whole numbers only.")
except ZeroDivisionError:
    print("You can't divide by zero!")
  • Here the conversions succeed, but a / b is 8 / 0, which raises a ZeroDivisionError.
  • Python checks each except in order and runs the one that matches, printing You can't divide by zero!.

You can list several except blocks, each handling a different type. This is far better than catching everything, because a specific catch only handles the problems you actually expect — and lets genuinely unexpected bugs surface so you can fix them.

A practical use: validating input

The most common real-world use of try/except is making user input safe. Whatever a person types arrives as text, and converting it to a number can fail. If you've used input and output, this makes those programs unbreakable.

age_text = input("How old are you? ")

try:
    age = int(age_text)
    print("Next year you'll be", age + 1)
except ValueError:
    print("That doesn't look like a number.")
  • input(...) always returns a string, so age_text might be "15" or "fifteen".
  • If it's "15", int(age_text) succeeds and the program prints the next age.
  • If it's "fifteen", the conversion raises a ValueError, the except runs, and the program politely explains instead of crashing.

Capturing the error message

You can grab the exception itself with as to learn more about what went wrong:

try:
    value = int("3.5")
except ValueError as error:
    print("Something went wrong:", error)
  • except ValueError as error: stores the exception object in error.
  • Printing it shows Python's own description of the problem, which is useful while debugging.

else and finally

Two optional extras complete the picture.

An else block runs only if the try finished without an error:

try:
    number = int("42")
except ValueError:
    print("Not a number.")
else:
    print("Success! The number doubled is", number * 2)

Because int("42") succeeds, the except is skipped and the else runs, printing Success! The number doubled is 84. Putting the "everything went fine" code in else keeps the try block focused only on the line that might fail.

A finally block runs no matter what — whether or not an exception happened. It's the place for cleanup, like closing a file:

try:
    print(10 / 0)
except ZeroDivisionError:
    print("Caught a division error.")
finally:
    print("This always runs.")

This prints Caught a division error. and then, unconditionally, This always runs.. Even if no except matched, finally would still execute.

Worked example: a safe calculator

Let's build a small division calculator that survives bad input and division by zero.

def safe_divide(top_text, bottom_text):
    try:
        top = int(top_text)
        bottom = int(bottom_text)
        result = top / bottom
    except ValueError:
        return "Both inputs must be whole numbers."
    except ZeroDivisionError:
        return "Cannot divide by zero."
    else:
        return f"{top} / {bottom} = {result}"

print(safe_divide("10", "2"))     # 10 / 2 = 5.0
print(safe_divide("10", "0"))     # Cannot divide by zero.
print(safe_divide("ten", "2"))    # Both inputs must be whole numbers.

How it works:

  1. The try block attempts both conversions and the division. Any of them might fail.
  2. If a conversion fails, ValueError is caught and a clear message is returned. If the bottom is zero, ZeroDivisionError is caught instead.
  3. If nothing failed, the else block builds and returns the result. By returning from inside the function, each path gives back exactly one clean answer.

Run all three calls and notice the program never crashes — every kind of bad input produces a helpful message instead.

Try it yourself

Turn the calculator into an interactive loop:

  • Repeatedly ask the user for two numbers with input().
  • Use try/except to catch a ValueError (non-numbers) and a ZeroDivisionError (dividing by zero), printing a friendly message for each.
  • Add an else block that prints the result only when the division succeeds.
  • Let the user type quit to stop. (Hint: pair this with a while loop that keeps going until they quit.)

Test it with "5" and "0", then "cat" and "3", then "20" and "4". A well-handled program should sail through all three without ever crashing.

Quick quiz

Test yourself and earn XP

What is an exception in Python?

Which block holds the code that might cause an error?

What error does int("hello") raise?

Why is it better to catch a specific exception than to catch everything?

When does a finally block run?

FAQ

In everyday speech people use them interchangeably, and in Python they are closely linked. A syntax error means your code is written incorrectly and won't even start to run — you must fix the typo. An exception happens while a correctly written program is running, when something goes wrong at that moment, such as dividing by zero or trying to convert bad input. try/except is for exceptions, the runtime kind. It cannot rescue a syntax error, because that code never runs at all.

Almost never in normal code. A bare except catches every possible exception, including ones you didn't anticipate and even some that signal the program should stop, like the user pressing Ctrl+C. That can hide real bugs and make problems much harder to debug. The good habit is to catch the specific exception you expect, such as except ValueError, so that genuinely unexpected errors still show up loudly and get fixed.