{"record":{"id":"1a33e4eef6ba9130","repo":"D4Vinci/Scrapling","slug":"invalid-xpath-selector-selector","errorCode":null,"errorMessage":"Invalid XPath selector: {selector}","messagePattern":"Invalid XPath selector: (.+?)","errorType":"exception","errorClass":"SelectorSyntaxError","httpStatus":null,"severity":"error","filePath":"scrapling/parser.py","lineNumber":694,"sourceCode":"            else:\n                if adaptive:\n                    log.warning(\n                        \"Argument `adaptive` will be ignored because `adaptive` wasn't enabled on initialization. Check docs for more info.\"\n                    )\n                elif auto_save:\n                    log.warning(\n                        \"Argument `auto_save` will be ignored because `adaptive` wasn't enabled on initialization. Check docs for more info.\"\n                    )\n\n                return self.__handle_elements(elements)\n\n        except (\n            SelectorError,\n            SelectorSyntaxError,\n            XPathError,\n            XPathEvalError,\n        ) as e:\n            raise SelectorSyntaxError(f\"Invalid XPath selector: {selector}\") from e\n\n    def find_all(\n        self,\n        *args: str | Iterable[str] | Pattern | Callable | Dict[str, str],\n        **kwargs: str,\n    ) -> \"Selectors\":\n        \"\"\"Find elements by filters of your creations for ease.\n\n        :param args: Tag name(s), iterable of tag names, regex patterns, function, or a dictionary of elements' attributes. Leave empty for selecting all.\n        :param kwargs: The attributes you want to filter elements based on it.\n        :return: The `Selectors` object of the elements or empty list\n        \"\"\"\n        if self._is_text_node(self._root):\n            return Selectors()\n\n        if not args and not kwargs:\n            raise TypeError(\"You have to pass something to search with, like tag name(s), tag attributes, or both.\")\n","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/parser.py#L676-L712","documentation":"The xpath() method failed to compile or evaluate the XPath expression. lxml raised XPathError/XPathEvalError (or cssselect raised a SelectorError) and scrapling re-raises it as SelectorSyntaxError with the original exception attached as __cause__. Note the message does not echo the underlying reason, so inspect __cause__ for details.","triggerScenarios":"Calling selector.xpath('<bad expr>') with invalid syntax like '//div[[', unsupported XPath 2.0+ functions (ends-with, matches, string-join), or expressions that return a non-node result in a context expecting nodes.","commonSituations":"Using XPath 2.0 functions that lxml's XPath 1.0 engine doesn't implement; unescaped quotes inside string literals of dynamically built expressions; expressions copied from XPath 2.0/3.0 tooling.","solutions":["Inspect e.__cause__ — the lxml XPathEvalError message names the unsupported function or syntax error.","Replace XPath 2.0 constructs: ends-with(x, y) -> substring(x, string-length(x) - string-length(y) + 1) = y; matches() -> re:test() from lxml's EXSLT extension.","Fix quoting: if the expression contains double quotes, wrap literals in single quotes or escape as &quot;.","Register lxml extension namespaces (xmlns:re) when using EXSLT regex functions."],"exampleFix":"# before\npage.xpath(\"//div[ends-with(@id, '-main')]\")  # SelectorSyntaxError\n\n# after\npage.xpath(\"//div[substring(@id, string-length(@id) - 4) = '-main']\")","handlingStrategy":"try-catch","validationCode":"from lxml import etree\n\ndef xpath_is_valid(expr: str) -> bool:\n    try:\n        etree.XPath(expr)\n        return True\n    except etree.XPathError:\n        return False","typeGuard":null,"tryCatchPattern":"from scrapling.core.exceptions import SelectorSyntaxError\n\ntry:\n    nodes = page.xpath(expr)\nexcept SelectorSyntaxError as e:\n    cause = e.__cause__  # lxml XPathError has the real reason\n    logger.error('bad xpath %r: %s', expr, cause)\n    nodes = page.xpath('.//*')  # fallback or re-raise","preventionTips":["Remember scrapling uses XPath 1.0 via lxml — ends-with/matches/string-join do not exist.","Test xpath strings in isolation with lxml.etree.XPath() before wiring them into extraction pipelines.","When interpolating values into XPath literals, escape quotes carefully."],"tags":["xpath","selector","lxml","validation"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}