PyGuide

Learn Python with practical tutorials and code examples

Python What Error to Raise: Common Questions Answered

When writing Python code, knowing what error to raise in different situations is crucial for creating robust and maintainable applications. This guide answers the most common questions about Python exception handling and helps you choose the right error type for each scenario.

When Should I Raise ValueError vs TypeError? #

Use ValueError when the argument has the correct type but an inappropriate value:

def calculate_square_root(number):
    if not isinstance(number, (int, float)):
        raise TypeError("Expected int or float")
    if number < 0:
        raise ValueError("Cannot calculate square root of negative number")
    return number ** 0.5

# ValueError example
try:
    result = calculate_square_root(-4)
except ValueError as e:
    print(f"Value error: {e}")

Use TypeError when the argument has the wrong type entirely:

def concatenate_strings(str1, str2):
    if not isinstance(str1, str):
        raise TypeError("First argument must be a string")
    if not isinstance(str2, str):
        raise TypeError("Second argument must be a string")
    return str1 + str2

# TypeError example
try:
    result = concatenate_strings("Hello", 123)
except TypeError as e:
    print(f"Type error: {e}")

What Error Should I Raise for Missing Attributes? #

Use AttributeError when an object doesn't have a required attribute:

class Person:
    def __init__(self, name):
        self.name = name
    
    def get_email(self):
        if not hasattr(self, 'email'):
            raise AttributeError("Person object has no email attribute")
        return self.email

# AttributeError example
person = Person("Alice")
try:
    email = person.get_email()
except AttributeError as e:
    print(f"Attribute error: {e}")

When Should I Create Custom Exceptions? #

Create custom exceptions when built-in exceptions don't clearly describe your specific error condition:

class InsufficientFundsError(Exception):
    """Raised when account has insufficient funds for transaction"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f"Insufficient funds: ${balance} < ${amount}")

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance
    
    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        return self.balance

# Custom exception example
account = BankAccount(100)
try:
    account.withdraw(150)
except InsufficientFundsError as e:
    print(f"Transaction failed: {e}")

What Error to Raise for Invalid Operations? #

Use RuntimeError for generic runtime problems that don't fit other categories:

class DatabaseConnection:
    def __init__(self):
        self.connected = False
    
    def query(self, sql):
        if not self.connected:
            raise RuntimeError("Database connection not established")
        # Execute query logic here
        return "Query results"

# RuntimeError example
db = DatabaseConnection()
try:
    results = db.query("SELECT * FROM users")
except RuntimeError as e:
    print(f"Runtime error: {e}")

Use NotImplementedError for methods that should be implemented by subclasses:

class Animal:
    def make_sound(self):
        raise NotImplementedError("Subclasses must implement make_sound method")

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

# NotImplementedError example
animal = Animal()
try:
    sound = animal.make_sound()
except NotImplementedError as e:
    print(f"Implementation error: {e}")

How to Choose Between KeyError and ValueError for Dictionary Operations? #

Use KeyError when a dictionary key doesn't exist:

def get_user_data(user_id, users_dict):
    if user_id not in users_dict:
        raise KeyError(f"User ID {user_id} not found")
    return users_dict[user_id]

# KeyError example
users = {"123": "Alice", "456": "Bob"}
try:
    user = get_user_data("789", users)
except KeyError as e:
    print(f"Key error: {e}")

Use ValueError when the key format or value is invalid:

def validate_user_id(user_id):
    if not isinstance(user_id, str):
        raise TypeError("User ID must be a string")
    if len(user_id) != 3:
        raise ValueError("User ID must be exactly 3 characters")
    if not user_id.isdigit():
        raise ValueError("User ID must contain only digits")
    return user_id

# ValueError example
try:
    valid_id = validate_user_id("12")
except ValueError as e:
    print(f"Value error: {e}")

Summary #

Choosing what error to raise in Python depends on the specific situation:

  • ValueError: Correct type, wrong value
  • TypeError: Wrong type entirely
  • AttributeError: Missing attributes or methods
  • KeyError: Missing dictionary keys
  • RuntimeError: General runtime problems
  • NotImplementedError: Methods requiring implementation
  • Custom exceptions: Domain-specific error conditions

Understanding these distinctions helps you write more maintainable code and makes debugging easier for both you and other developers working with your code.