Python Exceptions: Try, Except, and Raise
Table of Contents
Python has two kinds of errors: syntax errors that prevent your code from running at all, and exceptions that happen while your code is executing. Knowing how to handle exceptions with try/except and how to raise your own is a core skill for writing reliable programs.
All the content from our Boot.dev courses are available for free here on the blog. This one is the “Errors” chapter of Learn to Code in Python. If you want to try the far more immersive version of the course, do check it out!
What Is the Difference Between Syntax Errors and Exceptions?
A syntax error means your code isn’t valid Python. The interpreter can’t even run it:
prnt("hello world)
File "<python-input-0>", line 1
prnt("hello world)
^
SyntaxError: unterminated string literal (detected at line 1)
An exception is different. Your code is valid Python, but something goes wrong during execution. For example, dividing by zero is syntactically fine — Python just can’t produce a result:
print(10 / 0)
# ZeroDivisionError: division by zero
Syntax errors must be fixed before you can run your program. Exceptions can be caught and handled gracefully so your program doesn’t crash.
How Does Try/Except Work in Python?
Python uses a try/except pattern for handling exceptions. The try block runs until an exception is raised or it completes, whichever happens first. The except block only executes if an exception is raised:
try:
10 / 0
except Exception:
print("can't divide by zero")
If you want to access the data from the exception, use the as keyword:
try:
10 / 0
except Exception as e:
print(e) # division by zero
Wrapping risky code in try/except blocks lets the program handle the problem without crashing. This is especially useful when working with user input, dictionary lookups, or list indexing — any operation where bad data might sneak in at runtime.
How Do You Raise Exceptions in Python?
Errors are not something to be scared of. Every program that runs in production manages errors on a constant basis. When something in your own code isn’t the “happy path”, you should raise an exception to let the caller know something went wrong:
def craft_sword(metal_bar):
if metal_bar == "bronze":
return "bronze sword"
if metal_bar == "iron":
return "iron sword"
if metal_bar == "steel":
return "steel sword"
raise Exception("invalid metal bar")
The raise keyword stops execution and forces the exception to be handled by the caller. This prevents bugs — if a function receives input it can’t work with, raising an exception is better than silently returning garbage.
An error is raised when something bad happens, but as long as your code handles it as users expect, it’s not a bug. A bug is when code behaves in ways users don’t expect.
Don’t catch your own exceptions
As a rule of thumb, don’t catch exceptions you raise within the same function:
# don't do this
def craft_sword(metal_bar):
try:
if metal_bar == "bronze":
return "bronze sword"
raise Exception("invalid metal bar")
except Exception as e:
print(f"An error occurred: {e}")
The caller should handle the error:
try:
craft_sword("gold bar")
except Exception as e:
print(e) # invalid metal bar
This keeps your functions focused on one job and lets each layer of code decide how to respond to failures.
What Are the Different Exception Types in Python?
Not all exceptions are the same. Python has a hierarchy of built-in exception types, each describing a specific kind of problem:
ZeroDivisionError— dividing by zeroIndexError— accessing a list index that doesn’t existKeyError— accessing a dictionary key that doesn’t existValueError— a function receives an argument with the right type but wrong valueTypeError— an operation is applied to the wrong type
You can catch specific exception types instead of the generic Exception:
try:
nums = [0, 1]
print(nums[2])
except IndexError:
print("index error")
except Exception as e:
print(e)
This prints index error because the IndexError handler matches first.
How Do You Catch Specific Exceptions in Python?
When handling exceptions, catch the most specific type first. Python stops checking once it finds a matching handler. If you catch a general Exception first, specific handlers below it will never run:
# wrong order — IndexError never gets caught specifically
try:
nums = [0, 1]
print(nums[2])
except Exception:
print("An error occurred")
except IndexError:
print("Index error")
The general Exception catches everything, so the IndexError branch is dead code. Always order your except clauses from most specific to most general:
try:
nums = [0, 1]
print(nums[2])
except IndexError:
print("Index error")
except Exception as e:
print(e)
Catching specific exceptions makes your code easier to debug and prevents you from accidentally swallowing errors you didn’t expect. This matters more as your programs grow — a generic except Exception might hide a bug in your loop logic or a typo in a variable name.
What Should You Learn After Python Exceptions?
Error handling is one of those skills that separates code that works from code that works reliably. Now that you understand try/except and raise, you’re ready to write programs that fail gracefully instead of crashing.
From here, most beginners move on to learning about sets or dive deeper into functions and code organization. If you want to keep going through the full Python curriculum with hands-on exercises, check out the Learn to Code in Python course on Boot.dev.
Frequently Asked Questions
What is the difference between a syntax error and an exception in Python?
A syntax error means your code is not valid Python and cannot run at all. An exception happens during execution when something goes wrong, like dividing by zero or accessing an invalid index. Syntax errors must be fixed before running. Exceptions can be caught and handled gracefully with try/except.
Should you catch all exceptions with a bare except clause?
No. Catching all exceptions with a bare except or except Exception hides bugs and makes debugging harder. Catch the most specific exception type you can so that unexpected errors still surface.
What is the difference between raise and return in Python?
return sends a value back to the caller and continues normal execution. raise stops normal execution and forces the caller to handle the error with a try/except block. Use raise when something has gone wrong and the function cannot produce a valid result.
Can you raise exceptions inside a try block?
Yes, you can raise exceptions anywhere, including inside a try block. If the raised exception matches an except clause in the same try block it will be caught there. However, as a rule of thumb, avoid catching exceptions you raise within the same function.
Related Articles
Python Sets: What They Are and How to Use Them
Mar 07, 2026 by lane
Sets are like lists, but with two key differences: they are unordered and they guarantee uniqueness. Only one of each value can exist in a set. If you need to track unique items or remove duplicates, sets are the tool for the job.
Python Dictionaries: How to Create and Use Them
Mar 06, 2026 by lane
Dictionaries are one of Python’s most useful data structures. Instead of accessing values by a numeric index like you do with lists, you access them by a key — usually a string. If lists are like numbered shelves, dictionaries are like labeled drawers.
Python Lists: A Complete Beginner Guide
Mar 05, 2026 by lane
A natural way to organize and store data is in a list. Some languages call them “arrays”, but in Python we just call them lists. Think of all the apps you use and how many of the items in them are organized into lists — a social media feed is a list of posts, an online store is a list of products, the state of a chess game is a list of moves.
Python Loops: For, While, Break, and Continue
Mar 04, 2026 by lane
Loops let you run the same code over and over without rewriting it each time. Whether you need to count through numbers, process items in a list, or keep going until a condition changes, Python gives you for loops and while loops to handle it.