If you need one try block to catch multiple exceptions from messy data, list the exception types in a tuple: except (ValueError, KeyError) as err:. Python runs that block when any exception in the tuple is raised.
Where people get stuck is deciding when one shared handler is fine and when each error needs its own fix.
In this tutorial, we’ll catch multiple exceptions in Python six ways, using one small set of US orders that breaks four different ways. I ran every script on Python 3.12.5, and the new syntax on 3.14.8.
The sample orders we’ll use to catch multiple exceptions
A small pricing function turns each order into a unit price with state sales tax. Only the first of five orders is clean:
A-1002:qtyis"two", aValueError.A-1003:qtyis"0", aZeroDivisionError.A-1004: ships to Guam, which isn’t inTAX, aKeyError.A-1005:qtyisNone, aTypeError.
For parsing text values, see converting a string to an integer and converting a string to a float in Python.
Unhandled, the loop dies on order A-1002:
TAX = {"TX": 0.0625, "CA": 0.0725, "NY": 0.04, "WA": 0.065}
orders = [
{"id": "A-1001", "state": "TX", "qty": "3", "total": "89.97"},
{"id": "A-1002", "state": "CA", "qty": "two", "total": "45.00"},
{"id": "A-1003", "state": "NY", "qty": "0", "total": "19.99"},
{"id": "A-1004", "state": "GU", "qty": "1", "total": "12.50"},
{"id": "A-1005", "state": "WA", "qty": None, "total": "30.00"},
]
def unit_price(order):
qty = int(order["qty"])
price = float(order["total"]) / qty
return round(price * (1 + TAX[order["state"]]), 2)
for order in orders:
print(order["id"], unit_price(order))
Output:
A-1001 31.86
Traceback (most recent call last):
File "C:\pyguides\orders.py", line 17, in <module>
print(order["id"], unit_price(order))
^^^^^^^^^^^^^^^^^
File "C:\pyguides\orders.py", line 11, in unit_price
qty = int(order["qty"])
^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'two'

int('two') stops the whole run with a ValueError.Method 1: Catch multiple exceptions in one except with a tuple (Recommended)
Use a tuple when every error type gets the same response: report the bad order and keep going. Same five orders, now wrapped in try:
from orders import orders, unit_price
for order in orders:
try:
print(f"{order['id']} ${unit_price(order):.2f}")
except (ValueError, ZeroDivisionError, KeyError, TypeError) as err:
print(f"{order['id']} skipped -> {type(err).__name__}: {err}")
Output:
A-1001 $31.86
A-1002 skipped -> ValueError: invalid literal for int() with base 10: 'two'
A-1003 skipped -> ZeroDivisionError: float division by zero
A-1004 skipped -> KeyError: 'GU'
A-1005 skipped -> TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

How does this code work?
Python compares the raised exception against each class in the tuple. For A-1002, ValueError matches, so the block runs with err holding the exception.
type(err).__name__ gives the class name, so one handler still says what went wrong. More in checking the type of a variable in Python.
Important: it must be a tuple (see creating a tuple in Python). A list compiles, then fails with TypeError: catching classes that do not inherit from BaseException is not allowed.
Method 2: Handle each exception differently with separate except blocks
A shared message isn’t always enough. A missing tax rate means updating a table; a zero quantity means the order is wrong.
So give each its own except block, plus else and finally:
from orders import orders, unit_price
checked = 0
for order in orders:
try:
price = unit_price(order)
except ValueError:
print(f"{order['id']} qty isn't a number: {order['qty']!r}")
except ZeroDivisionError:
print(f"{order['id']} qty is 0, can't split ${order['total']}")
except KeyError as err:
print(f"{order['id']} no sales tax rate for {err}")
except TypeError:
print(f"{order['id']} qty is missing")
else:
print(f"{order['id']} ${price:.2f}")
finally:
checked += 1
print(f"Checked {checked} orders")
Output:
A-1001 $31.86
A-1002 qty isn't a number: 'two'
A-1003 qty is 0, can't split $19.99
A-1004 no sales tax rate for 'GU'
A-1005 qty is missing
Checked 5 orders

else, and finally counts all five.How does this code work?
Python checks the except clauses top to bottom and runs only the first one that matches. The rest are skipped for that order.
else runs only when the try body raised nothing. finally runs every time, error or not, so the count stays honest.
My guide to the Python dictionary KeyError covers why keys go missing.
Method 3: Catch a parent exception class like LookupError or ArithmeticError
KeyError and IndexError both inherit from LookupError; ZeroDivisionError inherits from ArithmeticError.
Catching the parent catches every child, which is handy when they need the same fix. Same orders again:
from orders import orders, unit_price
for order in orders[2:4]:
try:
unit_price(order)
except LookupError as err:
print(order["id"], "LookupError caught", type(err).__name__)
except ArithmeticError as err:
print(order["id"], "ArithmeticError caught", type(err).__name__)
try:
unit_price(orders[3])
except Exception:
print("Exception matched first, so the KeyError block below never runs")
except KeyError:
print("never printed")
Output:
A-1003 ArithmeticError caught ZeroDivisionError
A-1004 LookupError caught KeyError
Exception matched first, so the KeyError block below never runs
How does this code work?
An except clause matches the class you name or any subclass of it. That’s why Guam’s KeyError fires the LookupError block.
The last try shows the trap: except Exception sits first and matches everything, so the KeyError block below it is dead code.
So put specific classes first and broad ones last. The same index error on its own is covered in fixing IndexError: list index out of range.
Method 4: Python 3.14 except without parentheses (PEP 758)
Python 3.14 lets you drop the parentheses when you list several exceptions and don’t use as. Here’s one script run on both versions, using the sample’s quantity values:
import sys
print("Python", sys.version.split()[0])
for qty in ["2", "two", None]:
try:
print(int(qty) * 10)
except ValueError, TypeError:
print(f"bad qty: {qty!r}")

SyntaxError: multiple exception types must be parenthesized; Python 3.14 runs it and handles both bad values.On 3.14 the output is:
Python 3.14.8
20
bad qty: 'two'
bad qty: None
Add as err, though, and 3.14 still wants them: SyntaxError: multiple exception types must be parenthesized when using 'as'.
Note: if your code has to run on 3.13 or older, keep the parentheses. A SyntaxError is unusual among the types of errors in Python: it fails before a single line runs.
Method 5: Ignore multiple exceptions with contextlib.suppress()
Sometimes a failure needs no message at all. contextlib.suppress() takes any number of exception classes and silently swallows them inside its with block:
from orders import orders, unit_price
from contextlib import suppress
prices = {}
for order in orders:
with suppress(ValueError, ZeroDivisionError, KeyError, TypeError):
prices[order["id"]] = unit_price(order)
print(prices)
print(f"{len(prices)} of {len(orders)} orders priced")
Output:
{'A-1001': 31.86}
1 of 5 orders priced
Only A-1001 gets a price: 1 of 5 orders.
How does this code work?
When a listed exception escapes the with block, suppress stops it there, and the assignment never happens.
It’s the same as try / except / pass, just shorter. Inside a Python for loop, the loop just moves on.
Pro Tip: only use suppress() when losing the record is truly fine. Four orders vanished here without a trace.
Method 6: Catch multiple exceptions raised together with except* and ExceptionGroup
Everything so far handles one exception at a time. To report every problem together, Python 3.11 added ExceptionGroup, plus except* to pull matches out of the group:
from orders import orders, unit_price
problems = []
for order in orders:
try:
unit_price(order)
except (ValueError, ZeroDivisionError, KeyError, TypeError) as err:
err.add_note(order["id"])
problems.append(err)
try:
raise ExceptionGroup("order import failed", problems)
except* (ValueError, TypeError) as eg:
print("Bad qty: ", [e.__notes__[0] for e in eg.exceptions])
except* ZeroDivisionError as eg:
print("Zero qty: ", [e.__notes__[0] for e in eg.exceptions])
except* KeyError as eg:
print("Unknown state:", [e.__notes__[0] for e in eg.exceptions])
Output:
Bad qty: ['A-1002', 'A-1005']
Zero qty: ['A-1003']
Unknown state: ['A-1004']

except* clause pulls out its own order IDs.How does this code work?
add_note() (also 3.11+) tags each exception with its order ID, and the group carries all four.
Unlike plain except, several except* clauses can run for one group, each getting just its matches.
Any type no clause matches is re-raised. To log full tracebacks instead, see printing a stack trace in Python.
Which method should you use to catch multiple exceptions?
| Situation | Use | Why |
|---|---|---|
| Same response for every error | except (A, B) as err: | One block; err names the type |
| Different fix per error | Separate except blocks | Own message or recovery |
| All children need one fix | Parent class (LookupError) | Covers every subclass |
Python 3.14+ only, no as | except A, B: | Less punctuation, same behavior |
| Failure is truly harmless | contextlib.suppress(A, B) | Shortest, but leaves no record |
| Several errors at once | ExceptionGroup + except* | Reports them all |
I reach for the tuple first and split it into separate blocks once the fixes differ.
Things to keep in mind when catching multiple exceptions
- Use a tuple, never a list. A list raises
TypeErroras soon as an exception arrives. - Order specific before broad.
except Exceptionplaced first hides every block below it. - Avoid a bare
except:. It also catchesKeyboardInterruptand theSystemExitfrom Python exit commands. - Keep the
trybody small. A wide block can hide bugs, like a ValueError: math domain error from an unrelated line.
A few more error guides you’ll probably want:
- Fix NameError: name is not defined in Python
- Fix UnboundLocalError in Python
- Retry until input is valid with a Python while loop
- Debug with the Python breakpoint() function
Frequently asked questions
How do I catch multiple exceptions in one line in Python?
Use a tuple: except (ValueError, KeyError) as err:. Python 3.14+ also accepts except ValueError, KeyError: without as.
Can I use a list instead of a tuple in an except clause?
No. A list compiles, but when an exception is raised Python fails with TypeError: catching classes that do not inherit from BaseException is not allowed.
How do I know which exception was caught?
Use as err, then type(err).__name__ or isinstance(err, KeyError).
Does the order of except blocks matter?
Yes. Python runs the first matching block only, so a parent class like Exception placed first hides the more specific blocks after it.
What’s the difference between except and except*?
except handles one exception. except* (Python 3.11+) handles an ExceptionGroup, and several except* clauses can run for the same group.
Where is exception handling documented?
See Handling Exceptions in the official Python tutorial.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn