{"id":"7d1982d97ba51800","repo":"aio-libs/aiohttp","slug":"bad-pattern-pattern-exc","errorCode":null,"errorMessage":"Bad pattern '{pattern}': {exc}","messagePattern":"Bad pattern '(.+?)': (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_urldispatcher.py","lineNumber":435,"sourceCode":"                continue\n\n            match = self.DYN_WITH_RE.fullmatch(part)\n            if match:\n                pattern += \"(?P<{var}>{re})\".format(**match.groupdict())\n                formatter += \"{\" + match.group(\"var\") + \"}\"\n                continue\n\n            if \"{\" in part or \"}\" in part:\n                raise ValueError(f\"Invalid path '{path}'['{part}']\")\n\n            part = _requote_path(part)\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile(pattern)\n        except re.error as exc:\n            raise ValueError(f\"Bad pattern '{pattern}': {exc}\") from None\n        assert compiled.pattern.startswith(PATH_SEP)\n        assert formatter.startswith(\"/\")\n        self._pattern = compiled\n        self._formatter = formatter\n\n    @property\n    def canonical(self) -> str:\n        return self._formatter\n\n    def add_prefix(self, prefix: str) -> None:\n        assert prefix.startswith(\"/\")\n        assert not prefix.endswith(\"/\")\n        assert len(prefix) > 1\n        self._pattern = re.compile(re.escape(prefix) + self._pattern.pattern)\n        self._formatter = prefix + self._formatter\n\n    def _match(self, path: str) -> dict[str, str] | None:\n        match = self._pattern.fullmatch(path)","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_urldispatcher.py#L417-L453","documentation":"Raised as ValueError by DynamicResource.__init__ when the compiled regex built from the path template fails to compile (re.error). After converting the template into a regex pattern, aiohttp runs re.compile; if the user-supplied regex inside {var:regex} is invalid, the underlying re.error is wrapped and re-raised with this message.","triggerScenarios":"Using an invalid regex in a variable constraint: app.router.add_get('/items/{id:[0-9', handler) (unclosed char class), '{id:(foo}' (unbalanced group), '{id:*}' (* is not a valid regex standalone), or any PCRE syntax Python's re rejects.","commonSituations":"Hand-writing regex constraints without testing; copy-paste truncating the regex; assuming glob syntax ('*' matches all) instead of regex; nested unescaped special chars.","solutions":["Test the regex in a Python shell with re.compile first, then paste it into the template.","Use valid regex: '/items/{id:[0-9]+}' for digits, '/items/{slug:[a-z-]+}' for slugs.","Remember the constraint is a full Python regex, not a glob — '*' alone is invalid.","Escape literals like '.' as '\\.' inside the constraint."],"exampleFix":"# before\napp.router.add_get('/items/{id:[0-9}', handler)\n\n# after\napp.router.add_get('/items/{id:[0-9]+}', handler)","handlingStrategy":"validation","validationCode":"import re\n\ndef validate_regex_constraint(pattern: str) -> str:\n    try:\n        re.compile(pattern)\n    except re.error as e:\n        raise ValueError(f\"Invalid regex in path constraint {pattern!r}: {e}\") from None\n    return pattern","typeGuard":"import re\n\ndef is_compilable_regex(pattern: str) -> bool:\n    try:\n        re.compile(pattern)\n        return True\n    except re.error:\n        return False","tryCatchPattern":"try:\n    app.router.add_get(path, handler)\nexcept ValueError as e:\n    raise ValueError(f\"Route regex failed to compile: {e}\") from e","preventionTips":["Test regex constraints with re.compile in a REPL before embedding them.","Remember the constraint is Python regex, not glob.","Add a startup test that registers all routes to catch bad regex early."],"tags":["aiohttp","routing","regex","path","value-error"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}