D4Vinci/Scrapling · error · ValueError
Expressions of type {__name__}.XPathExpr can ony join expres
Error message
Expressions of type {__name__}.XPathExpr can ony join expressions of the same type (or its descendants), got {type(other)} What it means
Raised by `XPathExpr.join` in scrapling/core/translator.py, Scrapling's cssselect extension that adds `::text` and `::attr()` pseudo-elements. When two CSS selector expressions are combined (comma grouping inside a selector like `div a, div b::text`), `join` requires `other` to be an `XPathExpr` (or subclass) so the `textnode`/`attribute` state carries over correctly. Passing a plain `cssselect.GenericTranslator` XPathExpr — which happens if a different translator or a raw expression object is mixed in — triggers this ValueError.
Source
Thrown at scrapling/core/translator.py:61
else:
path += "/text()"
if self.attribute is not None:
if path.endswith("::*/*"): # pragma: no cover
path = path[:-2]
path += f"/@{self.attribute}"
return path
def join(
self: Self,
combiner: str,
other: OriginalXPathExpr,
*args: Any,
**kwargs: Any,
) -> Self:
if not isinstance(other, XPathExpr):
raise ValueError( # pragma: no cover
f"Expressions of type {__name__}.XPathExpr can ony join expressions"
f" of the same type (or its descendants), got {type(other)}"
)
super().join(combiner, other, *args, **kwargs)
self.textnode = other.textnode
self.attribute = other.attribute
return self
# e.g. cssselect.GenericTranslator, cssselect.HTMLTranslator
class TranslatorProtocol(Protocol):
def xpath_element(self, selector: Element) -> OriginalXPathExpr: # pyright: ignore # pragma: no cover
pass
def css_to_xpath(self, css: str, prefix: str = ...) -> str: # pyright: ignore # pragma: no cover
pass
View on GitHub (pinned to 5d213a2d47)
Solutions
- Let Scrapling translate the whole CSS selector itself — pass the full selector string to `page.css('a::attr(href), a::text')` instead of pre-translating parts with cssselect.
- If you must combine programmatically, wrap the foreign expression first: `XPathExpr.from_xpath(raw_expr)` before joining.
- Check for stray `GenericTranslator`/`HTMLTranslator` usage in your code and replace with Scrapling's translator classes.
- Reproduce with a minimal selector to confirm which branch produces the non-Scrapling expression.
Example fix
# before
from cssselect import GenericTranslator
partial = GenericTranslator().css_to_xpath('div a')
selector.css(partial + '|//span') # mixing translators
# after
selector.css('div a, span') # one selector, one translator Defensive patterns
Strategy: validation
Validate before calling
from scrapling.core.translator import XPathExpr
from cssselect.xpath import XPathExpr as OriginalXPathExpr
def joinable(expr) -> bool:
return isinstance(expr, XPathExpr) Type guard
from scrapling.core.translator import XPathExpr
def is_scrapling_xpath_expr(expr) -> bool:
"""True if expr can be joined with Scrapling XPathExpr instances."""
return isinstance(expr, XPathExpr) Try / catch
try:
combined = expr_a.join(',', expr_b)
except ValueError as e:
# wrap foreign expressions first, then retry once
from scrapling.core.translator import XPathExpr
combined = expr_a.join(',', XPathExpr.from_xpath(expr_b)) Prevention
- Never mix stock cssselect translation output into Scrapling selector strings.
- Pass whole CSS selector strings to .css(); let Scrapling own the translation.
- Wrap foreign expressions with XPathExpr.from_xpath() before any join.
When it happens
Trigger: Combining selector expressions where one side was produced by a non-Scrapling translator (plain `GenericTranslator().selector_to_xpath(...)` result fed into a Scrapling CSS query chain), or calling `XPathExpr.join(combiner, other)` manually with a `cssselect.xpath.XPathExpr` instance. Typical user-facing selector: grouping with `::text`/`::attr()` across differently-translated branches.
Common situations: Mixing Scrapling's `HTMLTranslator` with stock cssselect translation output; code that pre-compiles part of a selector with `cssselect` directly and concatenates it into a `Selector.css()` query; upgrading Scrapling versions where the translator internals changed shape.
Related errors
- The functional pseudo-element ::{pseudo_element.name}() is u
- The pseudo-element ::{pseudo_element} is unknown
- Expected a single string or ident for ::attr(), got {functio
- Storage system must implement `save` method
- Storage system must implement `retrieve` method
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/03c39c316c466cef.
Report an issue: GitHub.