raise

Updated March 16, 2026 · Keywords
keyword exception error-handling control-flow

The raise statement in Python explicitly triggers an exception. It’s how you signal that something has gone wrong in your code—whether that’s invalid input, a violated constraint, or an unexpected state. Rather than silently continuing with bad data, raise stops execution and propagates an error up the call stack.

Syntax

raise  # Re-raise the current exception (must be in an except block)

raise ValueError("error message")  # Raise a built-in exception

raise CustomError("custom message")  # Raise a custom exception class

Basic Usage

Raise a built-in exception with a message:

def divide(a, b):
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    return a / b

divide(10, 0)
# Traceback (most recent call last):
#   File "<stdin>", line 3, in divide
# ZeroDivisionError: Cannot divide by zero

Raise different exception types for different errors:

def process_age(age):
    if not isinstance(age, int):
        raise TypeError("Age must be an integer")
    if age < 0:
        raise ValueError("Age cannot be negative")
    if age > 150:
        raise ValueError("Age seems unrealistic")
    return age

process_age("twenty")
# TypeError: Age must be an integer

process_age(-5)
# ValueError: Age cannot be negative

Raising Custom Exceptions

Define your own exception classes for domain-specific errors:

class ValidationError(Exception):
    """Raised when input fails validation."""
    pass

class AuthenticationError(Exception):
    """Raised when authentication fails."""
    pass

def login(username, password):
    if not verify_credentials(username, password):
        raise AuthenticationError("Invalid username or password")
    return True

Add custom behavior to exception classes:

class APIError(Exception):
    def __init__(self, message, status_code=None):
        super().__init__(message)
        self.status_code = status_code

def fetch_data(url):
    if not url.startswith("https://"):
        raise APIError("URL must use HTTPS", status_code=400)
    # ... fetch logic

try:
    fetch_data("http://example.com")
except APIError as e:
    print(f"Error {e.status_code}: {e}")
# Error 400: URL must use HTTPS

Re-Raising Exceptions

Use raise alone in an except block to re-raise the current exception:

def outer_wrapper():
    try:
        risky_operation()
    except ValueError as e:
        print(f"Caught error: {e}")
        raise  # Re-raise the same exception

def handle_with_context():
    try:
        outer_wrapper()
    except ValueError:
        print("Error propagated to top level")
        raise  # Continues propagating

This pattern lets you log errors while still propagating them:

import logging

def read_config(path):
    try:
        with open(path) as f:
            return json.load(f)
    except FileNotFoundError as e:
        logging.warning(f"Config file not found: {path}")
        raise  # Caller needs to know the file is missing
    except json.JSONDecodeError as e:
        logging.error(f"Invalid JSON in {path}: {e}")
        raise  # Config is invalid—caller must handle

Exception Chaining

Python 3 supports exception chaining with from:

try:
    int("not a number")
except ValueError as e:
    raise RuntimeError("Conversion failed") from e

Output:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int()...
The above exception was the direct cause of the following:
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Conversion failed

Use from None to suppress the original exception context:

try:
    sensitive_operation()
except PermissionError:
    raise AppError("Operation failed") from None

Raising in Different Contexts

In functions

def validate_email(email):
    if "@" not in email:
        raise ValueError(f"Invalid email: {email}")
    return True

def register_user(email, name):
    validate_email(email)  # May raise ValueError
    # ... continue registration

In classes

class BankAccount:
    def __init__(self, balance):
        if balance < 0:
            raise ValueError("Balance cannot be negative")
        self._balance = balance
    
    def withdraw(self, amount):
        if amount > self._balance:
            raise ValueError("Insufficient funds")
        self._balance -= amount
        return amount

In init and special methods

class PositiveInteger:
    def __init__(self, value):
        if not isinstance(value, int) or value <= 0:
            raise TypeError("Must be a positive integer")
        self.value = value

class OrderedPair:
    def __setattr__(self, name, value):
        if not hasattr(self, "_values_set") and len(self.__dict__) >= 2:
            raise AttributeError("Cannot set more than 2 values")
        super().__setattr__(name, value)

In generators

def number_stream(n):
    for i in range(n):
        if i == 13:
            raise ValueError("Unlucky number")
        yield i

Practical Patterns

Validation decorator

def validate_positive(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        if result < 0:
            raise ValueError(f"{func.__name__} returned negative value")
        return result
    return wrapper

@validate_positive
def calculate_diff(a, b):
    return a - b

Assert vs raise

Use assert for debugging and internal invariants, raise for runtime errors:

def divide(a, b):
    # Assert for programmer errors during development
    assert b != 0, "Developer error: divide by zero"
    
    # Raise for runtime errors from bad input
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    
    return a / b

Sentinel values vs raise

Instead of returning special values, raise exceptions:

# Bad - magic values
def find_user(users, name):
    for user in users:
        if user["name"] == name:
            return user
    return None  # Magic value

# Better - raise exception
def find_user(users, name):
    for user in users:
        if user["name"] == name:
            return user
    raise KeyError(f"User not found: {name}")

See Also