{"id":"e3dd3b89ca1119a8","repo":"aio-libs/aiohttp","slug":"options-route-was-set-already","errorCode":null,"errorMessage":"OPTIONS route was set already","messagePattern":"OPTIONS route was set already","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_urldispatcher.py","lineNumber":593,"sourceCode":"        return url\n\n    @staticmethod\n    def _get_file_hash(byte_array: bytes) -> str:\n        m = hashlib.sha256()  # todo sha256 can be configurable param\n        m.update(byte_array)\n        b64 = base64.urlsafe_b64encode(m.digest())\n        return b64.decode(\"ascii\")\n\n    def get_info(self) -> _InfoDict:\n        return {\n            \"directory\": self._directory,\n            \"prefix\": self._prefix,\n            \"routes\": self._routes,\n        }\n\n    def set_options_route(self, handler: Handler) -> \"ResourceRoute\":\n        if \"OPTIONS\" in self._routes:\n            raise RuntimeError(\"OPTIONS route was set already\")\n        route = ResourceRoute(\n            \"OPTIONS\", handler, self, expect_handler=self._expect_handler\n        )\n        self._routes[\"OPTIONS\"] = route\n        self._allowed_methods.add(\"OPTIONS\")\n        return route\n\n    async def resolve(self, request: Request) -> _Resolve:\n        path = request.rel_url.path_safe\n        method = request.method\n        # We normalise here to avoid matches that traverse below the static root.\n        # e.g. /static/../../../../home/user/webapp/static/\n        norm_path = os.path.normpath(path)\n        if IS_WINDOWS:\n            norm_path = norm_path.replace(\"\\\\\", \"/\")\n        if not norm_path.startswith(self._prefix2) and norm_path != self._prefix:\n            return None, set()\n","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_urldispatcher.py#L575-L611","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nresource.set_options_route(my_handler)  # app already set it\n\n# after\n# omit the manual call; let Application handle OPTIONS automatically\napp.router.add_route('OPTIONS', '/static/{tail:.*}', my_handler)  # if custom needed","handlingStrategy":"validation","validationCode":"def guard_options(resource):\n    if 'OPTIONS' in getattr(resource, '_routes', {}):\n        raise RuntimeError('OPTIONS route already set on this resource')\n    return resource","typeGuard":null,"tryCatchPattern":"try:\n    resource.set_options_route(handler)\nexcept RuntimeError as e:\n    if 'OPTIONS route was set already' in str(e):\n        log.debug('OPTIONS already configured, skipping')\n    else:\n        raise","preventionTips":["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."],"tags":["aiohttp","static-files","options","setup","runtime-error"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}