D4Vinci/Scrapling · error · TypeError

Nested dictionaries are not accepted, only string keys and s

Error message

Nested dictionaries are not accepted, only string keys and string values are accepted

What it means

A dict passed to find_all() as an attribute filter contained a non-string key or a non-string value. scrapling requires flat Dict[str, str] — nested dicts or dicts with int/list values are rejected with a TypeError because they cannot be translated into a CSS attribute selector.

Source

Thrown at scrapling/parser.py:731

        attributes: Dict[str, Any] = dict()
        tags: Set[str] = set()
        patterns: Set[Pattern] = set()
        results, functions, selectors = Selectors(), [], []

        # Brace yourself for a wonderful journey!
        for arg in args:
            if isinstance(arg, str):
                tags.add(arg)

            elif type(arg) in (list, tuple, set):
                arg = cast(Iterable, arg)  # Type narrowing for type checkers like pyright
                if not all(map(lambda x: isinstance(x, str), arg)):
                    raise TypeError("Nested Iterables are not accepted, only iterables of tag names are accepted")
                tags.update(set(arg))

            elif isinstance(arg, dict):
                if not all([(isinstance(k, str) and isinstance(v, str)) for k, v in arg.items()]):
                    raise TypeError(
                        "Nested dictionaries are not accepted, only string keys and string values are accepted"
                    )
                attributes.update(arg)

            elif isinstance(arg, re_Pattern):
                patterns.add(arg)

            elif callable(arg):
                if len(signature(arg).parameters) > 0:
                    functions.append(arg)
                else:
                    raise TypeError(
                        "Callable filter function must have at least one argument to take `Selector` objects."
                    )

            else:
                raise TypeError(f'Argument with type "{type(arg)}" is not accepted, please read the docs.')

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Stringify values: {k: str(v) for k, v in attrs.items()}.
  2. For multi-valued attributes like class lists, use a regex Pattern as a separate arg: find_all(re.compile(r'\b(a|b)\b')) or loop over each value.
  3. Unnest nested dicts into separate find_all calls, one attribute set at a time.

Example fix

# before
selector.find_all({'data-count': 3})  # TypeError

# after
selector.find_all({'data-count': '3'})
Defensive patterns

Strategy: type-guard

Validate before calling

attrs = {k: str(v) for k, v in attrs.items() if isinstance(k, str)}
selector.find_all(attrs)

Type guard

def is_str_str_dict(d) -> bool:
    return isinstance(d, dict) and all(
        isinstance(k, str) and isinstance(v, str) for k, v in d.items()
    )

Prevention

When it happens

Trigger: find_all({'class': ['a', 'b']}), find_all({'data-count': 3}), or find_all({'attrs': {'id': 'x'}}).

Common situations: Feeding unnormalized JSON/scraped data directly as attribute filters; assuming BeautifulSoup-style tolerance where find_all(attrs={'x': 1}) works.

Related errors


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