inspect.getmembers Silently Skips AttributeError but Crashes on Any Other Exception (tested)
inspect.getmembers() works by calling getattr() on every name dir() reports and collecting whatever doesn't fail. Its source wraps that call in try/except AttributeError only -- nothing broader. A property getter that raises AttributeError is treated as "this attribute doesn't really exist" and silently dropped from the results, matching normal getattr() semantics. A property getter that raises anything else -- ValueError, a custom exception, a typo'd KeyError -- is not caught at all, so it propagates straight out of getmembers() and aborts the entire call, discarding every other attribute it already found.
1. One buggy property takes down introspection of the whole object
import inspect
class Widget:
@property
def ok(self):
return 42
@property
def broken(self):
raise ValueError("not ready yet")
w = Widget()
try:
members = inspect.getmembers(w)
print("got", len(members), "members")
except Exception as e:
print("getmembers() raised:", type(e).__name__, e)
getmembers() raised: ValueError not ready yet
Measured: getmembers() never returns -- not even the perfectly healthy ok property survives. A single buggy property anywhere on the object (or any of its base classes) is enough to make introspecting the entire object fail, which is a surprising amount of blast radius for a function usually reached for specifically because something needs debugging.
2. The one exception type that fails quietly: AttributeError
import inspect
class Widget:
@property
def ok(self):
return 42
@property
def missing(self):
raise AttributeError("not available right now")
w = Widget()
members = inspect.getmembers(w)
names = [n for n, v in members]
print("ok" in names, "missing" in names)
True False
Measured: with AttributeError specifically, getmembers() completes normally -- it just omits missing from the results, as if the attribute genuinely didn't exist. Swap that one exception type for ValueError, TypeError, or anything else, and the entire call aborts instead, per experiment 1. The two cases look like they should behave the same way from the caller's side -- "a property getter failed" -- but only one of them degrades gracefully.
3. Why: the standard library only catches AttributeError
import inspect
print(inspect.getsource(inspect._getmembers))
Measured: inspect._getmembers() (the shared implementation behind getmembers and getmembers_static) wraps each getattr() call in try: ... except AttributeError: ... with no other exception type handled -- confirmed directly from the CPython 3.13.5 source via inspect.getsource. Any property, __getattr__, or descriptor that can raise something other than AttributeError on failure is a latent landmine for any code that calls getmembers() on instances of that class, including generic debugging/logging utilities that weren't written with that specific class in mind.
Frequently asked questions
Does inspect.getmembers() skip a property that raises an exception?
It depends on the exception type. We measured that a property raising AttributeError is silently skipped (treated as if the attribute doesn't exist), but a property raising any other exception -- ValueError, TypeError, a custom exception -- aborts the entire getmembers() call, discarding results for every other attribute too.
Why does only AttributeError get swallowed?
Because inspect._getmembers(), the shared implementation behind getmembers(), wraps its getattr() calls in try/except AttributeError specifically -- confirmed by reading the actual CPython 3.13.5 source with inspect.getsource(inspect._getmembers). No other exception type is caught.
How do I safely introspect an object that might have a buggy property?
Don't rely on getmembers() alone for untrusted/buggy classes -- catch exceptions around the call itself, or iterate dir(object) and call getattr(object, name, default) with a sentinel default per-attribute instead, which isolates one failing attribute from the rest.
Does this affect inspect.getmembers_static too?
No -- we measured getmembers_static() returning successfully for the same buggy class, because it's documented to skip the descriptor protocol entirely: for a property it returns the property object itself from the class dict, without ever calling the getter, so the getter's exception never has a chance to fire.
Written with AI assistance. Measured on 2026-10-08 with Python 3.13.5's built-in inspect.getmembers: created a class with three properties -- one that returns normally, one that raises AttributeError, and one that raises ValueError -- then called inspect.getmembers() on an instance and compared the outcome with each property present. PlainHeaders is our extension; Python's inspect module is built in.