Define custom exceptions in Python
Create application exceptions from Exception or a specific built-in type, preserve normal exception behavior, and expose structured error details.
Define a class derived from Exception, or from a more specific built-in exception when its meaning fits. Use an Error suffix for ordinary application errors and keep the exception hierarchy understandable to callers.
Start with a small exception class
class AppError(Exception):
pass
try:
raise AppError("Configuration could not be loaded")
except AppError as exc:
print(str(exc))
A custom initializer is unnecessary when all you need is an error message. The inherited initializer already stores arguments and provides a string representation.
When you need structured details, add attributes while preserving the base initializer:
class InvalidConfigError(ValueError):
def __init__(self, message, *, field):
super().__init__(message)
self.field = field
error = InvalidConfigError("Timeout must be positive", field="timeout")
print(str(error)) # Timeout must be positive
print(error.args) # ('Timeout must be positive',)
print(error.field) # timeout
Callers can catch InvalidConfigError precisely or catch it through ValueError. Choose that base because the failure is an invalid value, not merely to reuse a class name.
Define a project-level hierarchy
class AppError(Exception):
pass
class DatabaseError(AppError):
pass
class ConfigError(AppError):
pass
except AppError handles this project's error family, while specific handlers can distinguish database and configuration failures. Put the more specific handlers first. Catching a broad family does not remove the need to log, report, or recover from the failure appropriately.
FAQ
Should I inherit from BaseException? Ordinary application errors should derive from Exception. BaseException also covers control-flow exceptions such as SystemExit and KeyboardInterrupt; a direct subclass would not be caught by except Exception.
Do I need __str__? Usually not. Pass the message to the base initializer. Override string formatting only when there is a concrete display requirement.
Where should extra information go? Store stable fields such as an error code or field name as attributes, rather than requiring callers to parse the message. Avoid embedding secrets in messages or payloads likely to be logged.
What if the custom error wraps another exception? Use raise AppError("Loading failed") from exc inside the handler to retain the causal relationship for debugging.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan