aio-libs/aiohttp · error · ValueError
Prefix cannot be empty
Error message
Prefix cannot be empty
What it means
Raised by Application.add_subapp when prefix, after rstrip('/'), is empty. A subapp must be scoped under a non-empty path segment; mounting at '' would intercept every request including ones meant for the parent, which is ambiguous and almost never intended. aiohttp rejects this with ValueError rather than guessing the user meant the root.
Source
Thrown at aiohttp/web_app.py:280
def reg_handler(signame: str) -> None:
subsig = getattr(subapp, signame)
async def handler(app: "Application") -> None:
await subsig.send(subapp)
appsig = getattr(self, signame)
appsig.append(handler)
reg_handler("on_startup")
reg_handler("on_shutdown")
reg_handler("on_cleanup")
def add_subapp(self, prefix: str, subapp: "Application") -> PrefixedSubAppResource:
if not isinstance(prefix, str):
raise TypeError("Prefix must be str")
prefix = prefix.rstrip("/")
if not prefix:
raise ValueError("Prefix cannot be empty")
factory = partial(PrefixedSubAppResource, prefix, subapp)
return self._add_subapp(factory, subapp)
def _add_subapp(
self, resource_factory: Callable[[], _Resource], subapp: "Application"
) -> _Resource:
if self.frozen:
raise RuntimeError("Cannot add sub application to frozen application")
if subapp.frozen:
raise RuntimeError("Cannot add frozen application")
resource = resource_factory()
self.router.register_resource(resource)
self._reg_subapp_signals(subapp)
self._subapps.append(subapp)
subapp.pre_freeze()
return resource
def add_domain(self, domain: str, subapp: "Application") -> MatchedSubAppResource:View on GitHub (pinned to c0ef574e29)
Solutions
- Provide a non-empty, non-/ prefix: '/v1', '/admin', etc.
- If you actually want everything routed through one app, do not use add_subapp — configure that app directly.
- Validate at config load: `if not prefix or prefix == '/': raise ValueError('non-root prefix required')`.
Example fix
// before
app.add_subapp('/', subapp) # ValueError
// after
app.add_subapp('/api', subapp) Defensive patterns
Strategy: validation
Validate before calling
def safe_add_subapp(app, prefix, subapp):
if not isinstance(prefix, str):
raise TypeError('prefix must be str')
prefix = prefix.rstrip('/')
if not prefix:
raise ValueError('prefix cannot be empty')
return app.add_subapp(prefix, subapp) Prevention
- Require a non-root, non-empty path segment for subapps.
- Validate prefix at config load (not '' or '/').
- If you need root routing, configure the parent app directly.
When it happens
Trigger: Calling app.add_subapp('', subapp); add_subapp('/', subapp) (becomes '' after rstrip); add_subapp('///', subapp) (also collapses to ''); dynamically computed prefix that resolves to root.
Common situations: Default value of an optional config prefix; templating that yields '/' for the root deployment; refactoring that forgot to set the prefix; attempt to mount a default subapp at root.
Related errors
- Prefix must be str
- Domain must be str
- Cannot add sub application to frozen application
- Cannot add frozen application
- Compress wbits must between 9 and 15, zlib does not support
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/db434ee0c26fe2b5.json.
Report an issue: GitHub.