🚀 Supercharge your YouTube channel's growth with AI.
Try YTGrowAI FreeExceptions in Python: Types and Handling

Turning text into a whole number can fail when the text is invalid. An exception is an object Python raises when an operation cannot continue normally, and a try statement lets code respond to a known failure.
I’ll show how to handle expected input failures and raise an exception when an input breaks a function’s rule.
TL;DR
Catch the narrow exception your code can recover from, and let unrelated failures keep their useful traceback.
- ValueError means a value has the right general type but is unsuitable for the operation.
- Put only the operation that can fail inside try, then catch the expected type.
- Use else for success-only work and finally for cleanup.
- Raise a specific built-in or custom exception when a function’s input violates its contract.
What Is an Exception in Python?
An exception is an object Python raises when an operation cannot continue normally. A syntax error is detected while Python parses source code, while an exception such as ValueError occurs as valid statements execute.
Python organizes exceptions into classes, so a handler can match a family of related failures. Application exceptions usually derive from Exception. BaseException also covers process-control events such as KeyboardInterrupt and SystemExit.
| Exception | Typical cause | Useful response |
|---|---|---|
| ValueError | int(“twelve”) | Ask for a valid numeric value |
| TypeError | Adding incompatible types | Correct the caller’s type contract |
| ZeroDivisionError | Dividing by zero | Reject or handle a zero divisor |
| IndexError | Reading past a sequence boundary | Check the index or iterate over values |
| KeyError | Looking up an absent mapping key | Use a default or handle missing data |
| FileNotFoundError | Opening a missing path | Choose a fallback or report the path |
These examples cover frequent causes rather than every built-in type. Python’s built-in exception reference lists the full hierarchy. Consult it when a traceback names an unfamiliar parent class.
How to Handle and Raise Exceptions in Python
A try statement separates an operation that may fail from the response to a known failure. I ran the named example with its command and saw valid input converted while invalid input produced a clear message.
Step 1: Catch the expected input error
int() raises ValueError when text cannot represent an integer. Catch that type around conversion, rather than wrapping an entire program and concealing unrelated bugs.
def parse_count(text):
try:
count = int(text)
except ValueError as error:
raise ValueError("count must be a whole number") from error
else:
return count
for sample in ("12", "twelve"):
try:
print(parse_count(sample))
except ValueError as error:
print(f"Invalid input: {error}")
Run the command shown in the terminal capture to check both inputs. Its output is:
12
Invalid input: count must be a whole number

The first input returns a number. The second is caught and presented with a specific message. The conversion error remains available as the chained cause for debugging.
Step 2: Handle more than one expected type
A try block can have multiple except clauses. Python selects the first matching clause. Put a subclass handler first so its specific response remains reachable.
try:
position = int(input("Position: "))
item = ["red", "blue"][position]
except ValueError:
print("Enter a whole number")
except IndexError:
print("Choose 0 or 1")
else:
print(item)
Conversion can fail before indexing begins, and a valid number can still fall outside the list. The two handlers give the caller a useful correction. See how to catch multiple exceptions in Python for more examples.
Step 3: Use else for successful work and finally for cleanup
The try clause contains the operation that may fail. The else clause runs only after success, and the finally clause runs as control leaves the construct whether an exception occurred or not.
file = None
try:
file = open("settings.json", encoding="utf-8")
except OSError as error:
print(f"Could not open settings: {error}")
else:
text = file.read()
print(f"Read {len(text)} characters")
finally:
if file is not None:
file.close()
The try suite is kept small, so the OSError handler is tied to opening the file rather than accidentally treating a later bug as a missing-file case. For ordinary file handling, a with statement is preferable because it closes the file automatically:
with open("settings.json", encoding="utf-8") as file:
text = file.read()
Step 4: Raise an exception when an input breaks a rule
Raise an exception when a function cannot meet its documented contract. Use a built-in type for a familiar invalid value and define a custom class when callers need to distinguish a domain failure.
class InsufficientFundsError(Exception):
pass
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("amount must be positive")
if amount > balance:
raise InsufficientFundsError("amount exceeds balance")
return balance - amount
The example gives callers a named failure they can catch without confusing it with an invalid amount. A custom class can also hold structured details when a message alone is insufficient.
Exception Handling Edge Cases
Choose a handler based on what the current layer can do next. A command-line boundary can show a concise message, while a library function usually lets its caller decide how to recover.
| Case | What happens | Better choice |
|---|---|---|
| Bare except | Also catches process-control exceptions | Catch a specific Exception subtype |
| except Exception | Can hide unrelated application failures | Use only at a boundary with a clear recovery or logging action |
| Parent class before child | Child exception matches the parent clause first | Place the narrower type first |
| SyntaxError | Source fails during parsing, before normal execution | Fix the source because runtime handling cannot catch a parsing failure on that line |
| raise without an active exception | Raises RuntimeError | Use bare raise only inside an except handler to re-raise the current error |
When a lower-level failure needs a domain name, exception chaining keeps the original cause attached. Suppress that cause only when it exposes irrelevant implementation detail and the caller has another way to diagnose the failure.
Do not use exceptions as a substitute for every conditional check. They are useful when an operation can fail for reasons that are awkward or costly to predict, while an ordinary branch is clearer when the condition is already available. A handler should either recover, add context and re-raise, or report the failure at a boundary where the program can respond.
Think about the unit of work before continuing after an exception. In a command that processes independent files, one unreadable file may be reported while later files are still useful. In a transaction that updates several related records, continuing after a partial failure may leave the data inconsistent.
A retry can be safe when the operation’s contract says it is safe to repeat. If a previous request may have completed, check its result before sending the write again. Exception handling alone does not make a repeated operation safe.
Choose between a branch and an exception
Use an ordinary condition when the relevant state is already available and checking it is clear. For example, a dictionary lookup can use get when a missing key has a normal default. Use exception handling when the operation itself is the clearest way to discover whether it can proceed.
This choice affects clarity rather than the validity of the program. A check followed by an operation can become stale if another actor changes the state between those steps. In such cases, attempting the operation and handling its documented failure can be more reliable.
Preserve the traceback when re-raising
A bare raise inside an except handler propagates the active exception with its traceback. Raising the caught object again can change where the traceback appears to begin, which makes the route to the original failure harder to follow.
When a higher layer can add useful meaning, raise a new domain exception and chain it to the caught exception. When no translation is needed, use a bare raise after recording or cleaning up. Avoid catching an exception merely to immediately raise it unchanged.
Keep custom exceptions small and stable
A custom exception is part of a function’s interface when callers are expected to catch it. Document the condition that raises it and the data it carries, so callers can choose a response without parsing a human-readable message.
Prefer a small class hierarchy that reflects distinct recovery choices. A new class for every possible message creates more names to maintain without giving callers a new decision. Put a shared base class above related domain failures only when callers have a useful response for the whole family.
Keep a program running by handling expected failures
An exception left uncaught stops the current operation and propagates toward the program boundary. Handling an expected failure lets that boundary choose a fallback, ask for corrected input, or end one task while the rest of the process remains available.
For example, a batch importer can reject one malformed record and continue with the next record if each row is an independent unit of work. It should not continue after an error that may have left shared state inconsistent. Decide what remains valid before choosing to resume.
- Recover when a known condition has a safe alternative.
- Stop the current operation when its required data is missing.
- Let programming defects propagate during development instead of disguising them as user mistakes.
Return useful feedback without exposing internals
A user-facing message should describe what the user can change. For invalid numeric input, say that a whole number is required rather than showing a traceback or an internal file path.
Keep diagnostic detail separate from that message. The exception object may contain a path, database value or service response that helps an operator but should not be copied into an untrusted interface. A boundary can log technical context and display a short safe explanation.
Log failures at the boundary that owns the response
Logging is useful when a process cannot recover locally or when an operator must investigate a failed task. Record enough context to identify the operation, while avoiding secrets and personal data in exception messages.
Python logging methods accept an exception-information option that includes traceback details. Use it inside an exception handler, and avoid logging the same exception at every layer because repeated reports obscure where the failure was handled.
Close resources even when an operation fails
Files, locks and network connections may need release after both success and failure. A finally clause runs while control leaves the try statement, but a context manager is usually clearer for resources that support it.
The earlier file example uses a with statement for this reason. Its exit method closes the file after the indented suite, including when reading raises an exception. Prefer the context manager supplied by the resource rather than hand-writing cleanup when one exists.
Cleanup code should not accidentally replace the failure that triggered cleanup. Keep the cleanup action small, and use a context manager whose behavior is documented for the resource being managed.
For a quick refresher on the surrounding syntax, AskPython’s try-except handling guide covers the basic form. Python’s Errors and Exceptions tutorial explains chaining and cleanup in more depth.
Conclusion: Catch the Failure You Can Handle
Use exception handling at the boundary that can take a useful next action. Keep the lower-level cause attached when translating an error, and let unexpected failures remain visible during development.
For the complete list of built-in types, consult Python’s built-in exceptions reference. The tutorial’s sections on handling, raising and cleanup cover the language behavior behind these examples.
FAQ
These answers cover common questions about Python exceptions.
What is an exception in Python?
An exception is an object raised when an operation cannot proceed normally during execution. A syntax error is detected while Python parses source code.
Can Python use multiple except clauses?
Yes. Add multiple except clauses to one try statement and put specific exception classes before parent classes. Python runs the first matching handler.
How do you raise an exception in Python?
Use raise with an exception instance, such as raise ValueError(“amount must be positive”). Use a custom Exception subclass when callers need to distinguish a domain-specific failure.
Can you use try without except in Python?
A try statement can use finally without except, as in try/finally. It must have at least an except clause or a finally clause.


