Python online course

How to Raise Exceptions in Python

Learn how to use Python's raise statement for validation, choose useful exception types and messages, catch errors with try and except, and create custom exceptions.

An exception is a signal that an error or exceptional condition has occurred. Python can raise exceptions automatically, such as when code divides by zero or tries to use an undefined variable. You can also raise an exception yourself when your program detects an invalid, unexpected, or unsupported situation.

Manual exceptions are especially useful for validation. Validation checks whether a value, argument, or program state meets the rules required by the rest of the code. If it does not, raising an exception stops the ordinary flow and reports the problem to the code that can handle it.

Before using raise, review Python if statements, data types, and try/except statements.

The raise Statement

raise is the Python keyword used to explicitly trigger an exception. Its basic forms are:

raise ExceptionType
raise ExceptionType("descriptive message")

You can raise an exception class without a message:

raise ValueError

Python creates an instance of that exception class for you. More commonly, construct an exception instance with a message:

raise ValueError("The quantity must be greater than zero")

The message is human-readable information attached to the exception. It should explain what was invalid and, where useful, state the expected condition. If the exception is not handled, Python displays the message with the exception type.

Why Raise an Exception?

Raising an exception interrupts the current ordinary flow of execution. This is appropriate when continuing would produce an invalid result or hide a problem. Common reasons include:

  • Rejecting a function argument that violates a required rule.
  • Checking user input before using it.
  • Reporting an unsupported operation or program state.
  • Signaling a failure from reusable code to its caller.

Python raises some exceptions automatically. For example, converting an unsuitable string to an integer can produce a ValueError. Manual raising is different: your code deliberately decides that a condition should be treated as an error.

Choosing an Exception Type

Choose a type that accurately communicates the category of failure. ValueError is appropriate when a value has the correct general type but is unacceptable for the operation or rule. For example, an integer age of -3 is still an integer, but it is not a valid age.

Exception typeUse whenExample invalid condition
ValueErrorA value is the right general type but fails a value rule.A percentage is 120 when the range is 0 through 100.
TypeErrorAn operation receives an inappropriate type.A function expects a number but receives a list.
KeyErrorA required dictionary key is missing.Looking up user["email"] when the key is absent.
IndexErrorA sequence index is outside the available positions.Accessing item 5 in a three-item list.
RuntimeErrorA general runtime condition prevents an operation and no more specific built-in type fits.Attempting an operation while an object is in an invalid state.

Do not use ValueError for every failure. A specific exception type helps callers write precise except clauses and makes tracebacks easier to understand.

Raise an Exception from a Conditional Check

A common pattern is to test a value with if and raise an exception when a boundary or other requirement is violated:

def require_minimum(value, minimum):
    if value < minimum:
        raise ValueError(
            f"value must be at least {minimum}; got {value}"
        )
    return value

require_minimum(3, 10)

Here, the value 3 is below the required minimum of 10, so the function raises ValueError. Because this exception is unhandled in the example, execution does not continue to a statement after the raise in the current flow. The function also does not return a value for that call.

Raising from a function lets the function enforce its own preconditions. The caller can handle the failure or allow it to propagate:

def set_percentage(amount):
    if amount < 0 or amount > 100:
        raise ValueError("amount must be between 0 and 100")
    return amount

percentage = set_percentage(75)

Catching a Manually Raised Exception

A try block contains code that may raise an exception. An except block handles a matching exception raised inside its associated try block:

try:
    raise ValueError("The supplied value is invalid")
except ValueError:
    print("The value was rejected")

print("The program can continue here")

The ValueError is caught, so the handler runs instead of allowing that exception to terminate the program. The final print statement runs normally.

Prefer a specific handler that names the expected exception type:

try:
    set_percentage(150)
except ValueError as error:
    print(f"Could not set percentage: {error}")

The as error part stores the exception object in a variable so the handler can read its message. Avoid using a broad catch-all such as except: by default. It can hide unrelated programming errors, including errors you did not anticipate.

Raised and Handled Exception Outcomes

SituationHandler presentProgram behavior
Matching exception is raised and caughtYes, such as except ValueErrorThe handler runs, and execution can continue after the try/except statement.
Exception is raised without a matching handlerNoThe exception propagates outward and normally terminates the current program flow.
Exception is raised inside a function and handled by its callerYes, in the calling codeThe function stops at the raise, and the caller's matching handler runs.

Unhandled Exceptions and Tracebacks

An uncaught exception normally produces a traceback. A traceback is a diagnostic report showing the chain of calls and the source location where the unhandled exception occurred. It is followed by the exception class and message.

Traceback (most recent call last):
  ...
ValueError: amount must be between 0 and 100

The exact file paths and line numbers vary according to your machine, source file, and the call path. Read the last line first to identify the exception type and message, then inspect the traceback locations to find where the failure began.

Exception Propagation and Re-raising

Exception propagation is the movement of an exception outward through calling code until it is handled or reaches the Python interpreter. If a function raises an exception and has no matching handler, Python searches the caller, then that caller's caller, and so on.

Inside an except block, a bare raise re-raises the exception currently being handled. This preserves the original exception and traceback while allowing the current code to perform limited work, such as logging or cleanup:

def load_record():
    try:
        raise ValueError("record data is invalid")
    except ValueError:
        print("Recording diagnostic information")
        raise

try:
    load_record()
except ValueError as error:
    print(f"Caller handled the error: {error}")

Use bare raise only inside an active except block. A plain raise elsewhere does not have a current exception to re-raise.

Custom Exceptions

A custom exception is an application-defined exception class for a domain-specific failure. Define one by subclassing Exception when the built-in types do not describe the problem clearly. Custom exception names conventionally end in Error.

class InsufficientCreditsError(Exception):
    pass


def buy_item(credits, price):
    if credits < price:
        raise InsufficientCreditsError(
            f"need {price} credits, but have {credits}"
        )
    return credits - price

try:
    buy_item(4, 10)
except InsufficientCreditsError as error:
    print(f"Purchase declined: {error}")

The targeted handler catches the domain failure separately from unrelated errors such as a TypeError caused by an incorrect argument type.

Troubleshooting Raised Exceptions

The program stops after raise

Usually, no matching exception handler catches the raised exception. Add an appropriate except clause where recovery is intended, or allow the traceback to expose a validation or programming error that should be fixed by the caller.

The except block does not run

The handler may name a different type from the one raised. For example, raise ValueError matches except ValueError, not an unrelated handler such as except TypeError.

The exception message is vague

Raise the exception with concise details about the invalid value or violated requirement, such as the expected range and the received value.

A broad handler hides unrelated bugs

Catch the narrowest expected exception type and avoid silently suppressing failures. A specific handler makes unexpected errors visible instead of treating them as ordinary validation failures.

A custom exception is not caught

Check that the custom class subclasses Exception and that the except clause names that same class or an appropriate parent class.

Key Points

  • Use raise to explicitly signal an invalid, unexpected, or unsupported condition.
  • Use ValueError when a value is unacceptable for a rule, and choose other types when they better describe the failure.
  • Include a concise exception message explaining what was invalid and what was expected.
  • Use try and a matching, specific except clause when the caller can recover.
  • An unhandled exception produces a traceback and stops the current flow.
  • Exceptions propagate up the call stack until a matching handler is found.
  • Use custom exception classes when a domain-specific failure deserves its own name.