Exception

Subclass it for your own errors and catch it for "anything went wrong" — it deliberately excludes Ctrl+C and sys.exit().

InheritsBaseException›Exception
Base classPython 3 (all)Live demo
Exception(*args)
Raised by
raise Exception(msg) — better: a specific subclass
Message
whatever you pass: str(e) is the single arg, or repr(args)
Quick fix
class MyError(Exception): pass — then raise MyError(...)
Watch out
except Exception around a big block hides your own bugs

Demo

Live evaluation
except Exception catches whatever int() raises and reports it. Try something that is not a number.
Try:
Inputs
textstrstring to convert
Code
def to_int(s):
    try:
        return int(s)
    except Exception as e:
        return f'{type(e).__name__}: {e}'
to_int(' 42 ')
Result
42

In Trigger the catch-all turns every failure into a string — convenient, but notice it reports ValueError for '4.2' just as happily as for a typo; the same clause would also swallow a bug in your own code. In Handle, NotFound is caught by the first clause even though it is also an AppError and an Exception: order matters, specific first.

Constructor

NameTypeRequiredDescription
*argsobjectnoUsually one message string. All arguments are kept in e.args; no keyword arguments.

Attributes

AttributeTypeMeaning
argstupleConstructor arguments. A custom __init__ should pass the message to super().__init__ so args and str(e) stay meaningful.
__cause__BaseException | NoneSet by raise MyError(...) from original — keeps the low-level error in the traceback.
__context__BaseException | NoneThe exception being handled when this one was raised.
__notes__list[str]Notes added with add_note() (3.11+).

Common patterns

One base class per library
Callers can catch everything from your package with one except, or a single case precisely.
class PaymentError(Exception):
    """Base class for this package."""

class CardDeclined(PaymentError):
    pass

class GatewayTimeout(PaymentError):
    pass
Custom exception with data
Pass a readable message to super().__init__ and keep machine-readable details as attributes.
class HTTPError(Exception):
    def __init__(self, status, url):
        super().__init__(f'{status} for {url}')
        self.status = status
        self.url = url
Catch-all at the boundary only
A broad except Exception belongs at the top of a request, job or thread — log with the traceback and move on.
for job in jobs:
    try:
        job.run()
    except Exception:
        logger.exception('job %s failed', job.id)

Examples

1. Custom exception in two lines
class QuotaExceeded(Exception): pass try: raise QuotaExceeded('limit is 100 requests') except QuotaExceeded as e: r = str(e) r
Returns
'limit is 100 requests'
2. Uncaught custom exception
class QuotaExceeded(Exception): pass raise QuotaExceeded('limit is 100 requests')
Returns
QuotaExceeded: limit is 100 requests
3. Most built-in errors are Exceptions
[issubclass(c, Exception) for c in (ValueError, KeyError, OSError, KeyboardInterrupt)]
Returns
[True, True, True, False]
4. Catching the base catches subclasses
class AppError(Exception): pass class NotFound(AppError): pass try: raise NotFound('user 7') except AppError as e: r = f'{type(e).__name__}: {e}' r
Returns
'NotFound: user 7'
5. Forgetting super().__init__ loses args
class BadError(Exception): def __init__(self, code): self.code = code e = BadError(404) (e.args, str(e))
Returns
((404,), '404')
6. Several args show as a tuple
str(Exception('not found', 404))
Returns
"('not found', 404)"
7. Keyword arguments are rejected
Exception(message='x')
Returns
TypeError: Exception() takes no keyword arguments

Pitfalls

1. A wide except Exception hides bugs
The handler was meant for bad input, but it also catches the NameError from using the wrong variable name — the function silently returns the fallback forever.
Wide catch-all
def price(item):
    try:
        return round(float(item['price']) * 1.2, 2)
    except Exception:
        return 0.0
def total(items):
    try:
        return sum(price(i) for i in cart)  # wrong name
    except Exception:
        return 0.0
total([{'price': '10'}])
0.0
Specific exceptions
def price(item):
    try:
        return round(float(item['price']) * 1.2, 2)
    except (KeyError, ValueError):
        return 0.0
def total(items):
    return sum(price(i) for i in cart)  # wrong name
total([{'price': '10'}])
NameError: name 'cart' is not defined
2. Raising plain Exception
Callers cannot catch a generic Exception precisely — they are forced into a catch-all. Raise a specific built-in or your own subclass.
raise Exception
def load(path):
    raise Exception('file is empty')
try:
    load('a.csv')
except ValueError:
    r = 'handled'
r
Exception: file is empty
raise a subclass
class EmptyFileError(ValueError):
    pass
def load(path):
    raise EmptyFileError('file is empty')
try:
    load('a.csv')
except ValueError:
    r = 'handled'
r
'handled'
3. Broad handler listed first
except clauses are checked in order. A general clause above a specific one makes the specific one dead code.
General first
try:
    {}['id']
except Exception:
    r = 'generic'
except KeyError:
    r = 'missing key'
r
'generic'
Specific first
try:
    {}['id']
except KeyError:
    r = 'missing key'
except Exception:
    r = 'generic'
r
'missing key'

When to use

Use it
  • Base class for your own exception hierarchy
  • Catch-all at a boundary: top of a request handler, worker loop, CLI main — with logging
  • isinstance(e, Exception) to tell ordinary errors from Ctrl+C / exit
Reach for something else
  • raise Exception(...) → raise ValueError, TypeError or your own subclass
  • except Exception around a few lines where you know what can fail → catch that
  • Catching everything including Ctrl+C → you almost never want that (BaseException)

Notes

CPython impl
Objects/exceptions.c — Exception adds nothing to BaseException; it exists to separate errors from exit/interrupt signals
Not caught by it
KeyboardInterrupt, SystemExit, GeneratorExit, BaseExceptionGroup (with non-Exception members)
Naming
By convention custom exception names end in Error (PEP 8)
Logging
logger.exception(msg) inside an except block logs the message plus the full traceback

FAQ

Subclass Exception (or a more specific built-in such as ValueError): class InvalidOrder(Exception): pass. Raise it with raise InvalidOrder('quantity must be positive'). If you add an __init__, pass the message on with super().__init__(message) so e.args and str(e) work.