D4Vinci/Scrapling · error · ValueError

`itertag` prefix {prefix!r} is not defined in `namespaces`

Error message

`itertag` prefix {prefix!r} is not defined in `namespaces`

What it means

The XML feed template resolves itertag prefixes against the class's namespaces mapping. When itertag is like 'atom:entry' and the prefix ('atom') is not a key in namespaces, _wanted_tag() raises ValueError because the namespace URI needed to match elements is unknown.

Source

Thrown at scrapling/spiders/templates/feed.py:81

        for node in self._iter_nodes(root):
            async for result in self.parse_node(response, node):
                yield result

    async def parse_node(
        self, response: "Response", node: _Element
    ) -> AsyncGenerator[Union[Dict[str, Any], Request, None], None]:
        """Override to process one feed node; `node` is a namespace-stripped `lxml` element."""
        raise NotImplementedError(f"{self.__class__.__name__} must implement parse_node() method")
        yield  # Make this a generator for type checkers

    def _wanted_tag(self) -> Tuple[Optional[str], str]:
        """Resolve `itertag` into a `(namespace uri or None, localname)` pair."""
        prefix, _, name = self.itertag.rpartition(":")
        if not prefix:
            return None, name
        uri = dict(self.namespaces).get(prefix)
        if not uri:
            raise ValueError(f"`itertag` prefix {prefix!r} is not defined in `namespaces`")
        return uri, name

    def _iter_nodes(self, root: _Element) -> Iterator[_Element]:
        uri, name = self._wanted_tag()
        for el in root.iter():
            if isinstance(el.tag, str):
                qname = etree.QName(el.tag)
                if qname.localname == name and (uri is None or qname.namespace == uri):
                    yield self._strip_namespaces(el)

    @staticmethod
    def _strip_namespaces(node: _Element) -> _Element:
        """Return a copy of `node` with namespaces removed from every tag and attribute."""
        node = deepcopy(node)
        for el in node.iter():
            if isinstance(el.tag, str):
                el.tag = etree.QName(el.tag).localname
            for key in list(el.attrib):

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Add the prefix->URI mapping to the class: namespaces = {"atom": "http://www.w3.org/2005/Atom"} and keep itertag = "atom:entry"
  2. Or use a localname-only itertag ("entry") if you want to match the tag in any namespace (uri is None matches all namespaces)

Example fix

// before
class Feed(XMLFeedSpider):
    itertag = "atom:entry"

// after
class Feed(XMLFeedSpider):
    itertag = "atom:entry"
    namespaces = {"atom": "http://www.w3.org/2005/Atom"}
Defensive patterns

Strategy: validation

Validate before calling

prefix = itertag.rpartition(":")[0]
if prefix and prefix not in dict(namespaces):
    raise ValueError(f"{prefix!r} missing from namespaces")

Prevention

When it happens

Trigger: Setting itertag = "atom:entry" without a matching namespaces = {"atom": "http://www.w3.org/2005/Atom"} on the class; typos in either the prefix or the namespaces key; overriding namespaces with an empty dict while keeping a prefixed itertag.

Common situations: Copy-pasting an itertag from feed examples without the namespace table that accompanied it; feeds that changed their namespace prefix over time; case mismatches between prefix and namespaces key.

Related errors


AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14). Data as JSON: /api/errors/689f2ac075472979. Report an issue: GitHub.