aio-libs/aiohttp · error · RuntimeError
OPTIONS route was set already
Error message
OPTIONS route was set already
What it means
Raised as RuntimeError by StaticResource.set_options_route when an OPTIONS route has already been registered on that static resource. The Application calls set_options_route automatically to add automatic OPTIONS handling; calling it again (or the app doing so twice) indicates a double-setup that would conflict.
Source
Thrown at aiohttp/web_urldispatcher.py:593
return url
@staticmethod
def _get_file_hash(byte_array: bytes) -> str:
m = hashlib.sha256() # todo sha256 can be configurable param
m.update(byte_array)
b64 = base64.urlsafe_b64encode(m.digest())
return b64.decode("ascii")
def get_info(self) -> _InfoDict:
return {
"directory": self._directory,
"prefix": self._prefix,
"routes": self._routes,
}
def set_options_route(self, handler: Handler) -> "ResourceRoute":
if "OPTIONS" in self._routes:
raise RuntimeError("OPTIONS route was set already")
route = ResourceRoute(
"OPTIONS", handler, self, expect_handler=self._expect_handler
)
self._routes["OPTIONS"] = route
self._allowed_methods.add("OPTIONS")
return route
async def resolve(self, request: Request) -> _Resolve:
path = request.rel_url.path_safe
method = request.method
# We normalise here to avoid matches that traverse below the static root.
# e.g. /static/../../../../home/user/webapp/static/
norm_path = os.path.normpath(path)
if IS_WINDOWS:
norm_path = norm_path.replace("\\", "/")
if not norm_path.startswith(self._prefix2) and norm_path != self._prefix:
return None, set()
View on GitHub (pinned to c0ef574e29)
Solutions
- Do not call set_options_route manually on a StaticResource — the Application handles it.
- Ensure Application.freeze()/startup runs only once per instance; create a fresh Application per test/process.
- If you need custom OPTIONS behavior, register an explicit OPTIONS route via add_route instead of set_options_route.
Example fix
# before
resource.set_options_route(my_handler) # app already set it
# after
# omit the manual call; let Application handle OPTIONS automatically
app.router.add_route('OPTIONS', '/static/{tail:.*}', my_handler) # if custom needed Defensive patterns
Strategy: validation
Validate before calling
def guard_options(resource):
if 'OPTIONS' in getattr(resource, '_routes', {}):
raise RuntimeError('OPTIONS route already set on this resource')
return resource Try / catch
try:
resource.set_options_route(handler)
except RuntimeError as e:
if 'OPTIONS route was set already' in str(e):
log.debug('OPTIONS already configured, skipping')
else:
raise Prevention
- Never call set_options_route manually; let the Application configure OPTIONS.
- Create a fresh Application per process/test to avoid double-setup.
- Register explicit OPTIONS routes via add_route if you need custom handling.
When it happens
Trigger: Internally invoked by Application setup to add automatic OPTIONS support to a static resource; raised if setup runs twice on the same StaticResource, or if user code calls resource.set_options_route(handler) after the Application already did.
Common situations: Manually calling set_options_route on a static resource that the Application has already configured; re-freezing/re-starting the same Application; duplicate setup paths in test fixtures.
Related errors
- Cannot change apps stack after .freeze() call
- Added route will never be executed, method {route.method} is
- '{directory}' does not exist
- '{directory}' is not a directory
- .url_for() is not supported by sub-application root
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/e3dd3b89ca1119a8.json.
Report an issue: GitHub.