aio-libs/aiohttp · error · KeyError

{key}

Error message

{key}

What it means

Raised by ChainMapProxy.__getitem__ as KeyError(key) when the key is absent from every backing mapping. ChainMapProxy backs Application/request/response storage, so requesting a storage key that was never stored re-raises the raw key as the KeyError message (the '{key}' template).

Source

Thrown at aiohttp/helpers.py:983

    def __init_subclass__(cls) -> None:
        raise TypeError(
            f"Inheritance class {cls.__name__} from ChainMapProxy is forbidden"
        )

    @overload  # type: ignore[override]
    def __getitem__(self, key: AppKey[_T]) -> _T: ...

    @overload
    def __getitem__(self, key: str) -> Any: ...

    def __getitem__(self, key: str | AppKey[_T]) -> Any:
        for mapping in self._maps:
            try:
                return mapping[key]
            except KeyError:
                pass
        raise KeyError(key)

    @overload  # type: ignore[override]
    def get(self, key: AppKey[_T], default: _S) -> _T | _S: ...

    @overload
    def get(self, key: AppKey[_T], default: None = ...) -> _T | None: ...

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

    def get(self, key: str | AppKey[_T], default: Any = None) -> Any:
        try:
            return self[key]
        except KeyError:
            return default

    def __len__(self) -> int:
        # reuses stored hash values if possible

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Use .get(key, default) instead of [key] for optional entries.
  2. Ensure the key is set in an on_startup handler before readers run.
  3. Verify the Application instance is the same one (sub-app vs parent) where the key lives.

Example fix

// before
val = request.app['feature_flag']  # KeyError if unset
// after
val = request.app.get('feature_flag', default_value)
Defensive patterns

Strategy: validation

Validate before calling

def safe_get(app, key, default=None):
    return app.get(key, default)

Type guard

def key_is_set(app, key) -> bool:
    return key in app

Try / catch

try:
    val = request.app[key]
except KeyError:
    val = default

Prevention

When it happens

Trigger: request.app['my_key'] or app['my_key'] before app['my_key'] = value was set; using a string key that was never registered; misspelling of an AppKey. Also ctx lookups through the proxy.

Common situations: Middleware fetching a key set by another middleware that didn't run; typo in key name; key set on a sub-application but read from the parent; lifecycle ordering (cleanup_ctx vs startup).

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/6e12de377685b35f.json. Report an issue: GitHub.