psf/requests · error · AttributeError

'{type(self).__name__}' object has no attribute '{key}'

Error message

'{type(self).__name__}' object has no attribute '{key}'

What it means

requests.structures.LookupDict (used for requests.codes, the status-code lookup) overrides __getattr__ to serve attribute access from the instance __dict__ and raise a standard-style AttributeError for anything not present. So requests.codes.ok works, but a misspelled or nonexistent code name raises this error. Note __getitem__ deliberately falls through to None instead, so bracket access never raises — an intentional asymmetry.

Source

Thrown at src/requests/structures.py:114

class LookupDict(dict[str, _VT]):
    """Dictionary lookup object."""

    name: Any

    def __init__(self, name: Any = None) -> None:
        self.name = name
        super().__init__()

    def __repr__(self) -> str:
        return f"<lookup '{self.name}'>"

    def __getattr__(self, key: str) -> _VT | None:
        # We need this for type checkers to infer typing
        # on attribute access with status_codes.py
        if key in self.__dict__:
            return self.__dict__[key]
        else:
            raise AttributeError(
                f"'{type(self).__name__}' object has no attribute '{key}'"
            )

    def __getitem__(self, key: str) -> _VT | None:  # type: ignore[override]
        # We allow fall-through here, so values default to None

        return self.__dict__.get(key, None)

    @overload
    def get(self, key: str, default: None = None) -> _VT | None: ...

    @overload
    def get(self, key: str, default: _D | _VT) -> _D | _VT: ...

    def get(self, key: str, default: _D | None = None) -> _VT | _D | None:
        return self.__dict__.get(key, default)

View on GitHub ↗ (pinned to 414f0513c3)

Solutions

  1. Fix the attribute name — check valid aliases in requests.status_codes (e.g. requests.codes.ok, requests.codes.not_found, requests.codes.teapot)
  2. Compare against integer literals or http.HTTPStatus instead: response.status_code == 404
  3. If a soft lookup is intended, use bracket access (requests.codes['maybe_missing'] returns None) or getattr with a default

Example fix

# before
if r.status_code == requests.codes.no_found:  # AttributeError
    ...

# after
if r.status_code == requests.codes.not_found:
    ...
Defensive patterns

Strategy: try-catch

Validate before calling

key = "Content-Type"
value = headers.get(key)  # returns None instead of raising

Type guard

def has_header(mapping, key):
    return key in mapping  # CaseInsensitiveDict membership is case-insensitive

Try / catch

try:
    value = obj.some_attr
except AttributeError:
    value = None  # attribute-style access on requests structures raises AttributeError for unknown keys

Prevention

When it happens

Trigger: Accessing an attribute that isn't a registered status-code name on requests.codes (e.g. requests.codes.okay, requests.codes.not_found_ with a typo), or attribute access on any other LookupDict instance for a key never inserted. Raised at src/requests/structures.py:110-116.

Common situations: Typos in status-code names (requests.codes.no_found); guessing names that aren't in the alias table; code written against dict-style access assuming attribute access has the same return-None behavior as lookup['missing']; static-analysis-invisible dynamic attributes making these errors appear only at runtime.

Related errors


AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31). Data as JSON: /data/errors/671f252897e54f03.json. Report an issue: GitHub ↗.