W3docs

Python Try...Except

Learn Python try, except, else, and finally blocks with clear examples. Handle ZeroDivisionError, ValueError, FileNotFoundError, and more.

When Python encounters an error at runtime, it raises an exception — an object that represents what went wrong. Without any handling, an exception terminates your program immediately. The try...except statement lets you catch these exceptions, respond to them gracefully, and keep your program running.

This chapter covers:

  • The try / except block — catching a specific exception
  • Catching exception details with as
  • Multiple except clauses and catching several exceptions at once
  • The else block — code that runs only when no exception occurs
  • The finally block — cleanup code that always runs
  • Common built-in exceptions and when they occur
  • Re-raising exceptions
  • Best practices and common mistakes

The basic try...except block

Wrap the code that might fail in a try block. If Python raises an exception, execution jumps to the matching except block instead of crashing.

python— editable, runs on the server

Output:

Error: division by zero

Python attempts the division, raises ZeroDivisionError, and the except block handles it. The as e clause binds the exception object to e so you can inspect or log the message.

If the try block succeeds, the except block is skipped entirely.

Catching a specific exception type

Always name the exception type you expect. Catching a named type makes your intent clear and avoids accidentally hiding unrelated bugs.

try:
    number = int("abc")
except ValueError as e:
    print(f"Could not convert: {e}")

Output:

Could not convert: invalid literal for int() with base 10: 'abc'

int("abc") raises ValueError because "abc" is not a valid integer. Specifying ValueError in the except clause means any other unexpected exception will still propagate and surface as an error rather than being silently swallowed.

Multiple except clauses

A single try block can have several except clauses — Python checks them top to bottom and executes the first match.

def safe_index(items, index):
    try:
        return items[index]
    except IndexError:
        print("Index out of range.")
    except TypeError:
        print("Index must be an integer.")

safe_index([1, 2, 3], 10)   # IndexError
safe_index([1, 2, 3], "a")  # TypeError

Output:

Index out of range.
Index must be an integer.

Order matters: place more specific exception types before broader ones so the specific handler runs first.

Catching multiple exceptions in one clause

When two or more exceptions deserve the same response, group them in a tuple:

try:
    value = int("not-a-number")
except (ValueError, TypeError) as e:
    print(f"Input error: {e}")

Output:

Input error: invalid literal for int() with base 10: 'not-a-number'

The else block

The else block runs only when the try block completes without raising any exception. Use it for code that should run on success but does not itself need error protection:

try:
    result = 10 / 2
except ZeroDivisionError:
    print("Cannot divide by zero.")
else:
    print(f"Division succeeded. Result: {result}")

Output:

Division succeeded. Result: 5.0

Keeping success-path logic in else (rather than at the bottom of try) prevents accidentally catching exceptions that the success-path code itself might raise.

The finally block

The finally block executes no matter what — whether the try block succeeds, an exception is caught, or an exception propagates uncaught. Use it for cleanup: closing files, releasing locks, or disconnecting from a database.

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Error caught.")
finally:
    print("This always runs — cleanup goes here.")

Output:

Error caught.
This always runs — cleanup goes here.

Even if you comment out the except block, finally still executes before Python propagates the exception.

Full structure at a glance

try:
    # code that may raise an exception
except SomeException as e:
    # handle the exception
except (AnotherError, YetAnother):
    # handle either of these
else:
    # runs only when try succeeded
finally:
    # always runs

Common built-in exceptions

ExceptionWhen it occurs
ZeroDivisionErrorDivision or modulo by zero
ValueErrorRight type, wrong value (e.g. int("abc"))
TypeErrorOperation applied to wrong type
IndexErrorSequence index out of range
KeyErrorDictionary key not found
FileNotFoundErrorFile or directory does not exist
AttributeErrorObject has no such attribute
ImportErrorModule cannot be imported
NameErrorVariable name is not defined

All of these inherit from the base class Exception. You can catch Exception to handle any of them in one clause, but prefer specific types where possible.

Handling a missing file

try:
    with open("data.txt", "r") as file:
        content = file.read()
except FileNotFoundError:
    print("Error: File not found.")

Output (when data.txt does not exist):

Error: File not found.

Re-raising an exception

Sometimes you want to log an exception or do partial cleanup, but still let it propagate to the caller. Use a bare raise inside an except block:

def process():
    try:
        result = 10 / 0
    except ZeroDivisionError:
        print("Logging error...")
        raise  # re-raises the original ZeroDivisionError

try:
    process()
except ZeroDivisionError as e:
    print(f"Outer handler caught: {e}")

Output:

Logging error...
Outer handler caught: division by zero

The bare raise preserves the original traceback so debugging is not harder than without the handler.

Catching the base Exception class

You can use Exception as a catch-all for any non-system-exiting error:

try:
    result = 10 / 0
except Exception as e:
    print(f"An error occurred: {type(e).__name__}: {e}")

Output:

An error occurred: ZeroDivisionError: division by zero

type(e).__name__ gives you the specific class name even when you catch via the base class. This is useful in top-level handlers where you want to log every unexpected error.

Bare except — and why to avoid it

A bare except (with no exception type) catches literally everything, including KeyboardInterrupt (Ctrl+C) and SystemExit, making your program hard to interrupt:

# Avoid this pattern
try:
    result = 10 / 0
except:
    print("Some error occurred")

Prefer except Exception if you need a broad catch, because it still lets KeyboardInterrupt and SystemExit propagate normally.

Best practices

  • Be specific. Catch the narrowest exception type that makes sense.
  • Do not silence exceptions. At minimum log the error; never leave an except block empty.
  • Use else for success-path code. This keeps the try block as small as possible.
  • Use finally for cleanup. Or, even better, use a with statement — see Python with Statement.
  • Avoid bare except. Use except Exception if you need a wide net.
  • Re-raise when appropriate. If you cannot fully handle the error, let it propagate with raise.

For raising exceptions deliberately and creating your own exception classes, see Python raise and Custom Exceptions.

Practice

Practice
What is the functionality of 'Try' and 'Except' in Python?
What is the functionality of 'Try' and 'Except' in Python?
Was this page helpful?