scrapy/scrapy · error · ValueError

{self.__class__.__name__}.__init__() received both response

Error message

{self.__class__.__name__}.__init__() received both response and text

What it means

Selector (scrapy.selector.Selector, the unified wrapper over parsel) raises ValueError in __init__ when both response and text are passed. A selector is constructed from exactly one source: a Response object (using its body/encoding) or a raw text string. Supplying both is ambiguous, so it is rejected immediately.

Source

Thrown at scrapy/selector/unified.py:71

    .. note:: JSON selector support requires ``parsel`` 1.8.0 or higher. With
       older versions setting ``type`` to ``"json"`` or ``"text"`` is not
       supported.
    """

    __slots__ = ["response"]
    selectorlist_cls = SelectorList

    def __init__(
        self,
        response: TextResponse | None = None,
        text: str | None = None,
        type: SelectorType | None = None,  # noqa: A002
        root: Any | None = _NOT_SET,
        **kwargs: Any,
    ):
        if response is not None and text is not None:
            raise ValueError(
                f"{self.__class__.__name__}.__init__() received both response and text"
            )

        # A response that is neither HTML nor XML, e.g. a JSON one, keeps type
        # unset, so that parsel determines it from the body.
        if type is None:
            if isinstance(response, XmlResponse):
                type = "xml"  # noqa: A001
            elif response is None or isinstance(response, HtmlResponse):
                type = "html"  # noqa: A001

        if text is not None:
            response = _response_from_text(text, type)

        if response is not None:
            text = response.text
            kwargs.setdefault("base_url", get_base_url(response))

View on GitHub (pinned to 06af687662)

Solutions

  1. Pass only one source: Selector(response=resp) or Selector(text=html_string).
  2. In wrapper functions, branch on which argument is provided before constructing.
  3. For raw bytes from a response, use response.text or let the response construct the selector itself (response.selector).

Example fix

# before
sel = Selector(response=response, text=response.text)  # ValueError

# after
sel = Selector(response=response)
Defensive patterns

Strategy: validation

Validate before calling

assert not (response is not None and text is not None), \
    'Selector accepts either response or text, not both'

Try / catch

try:
    sel = Selector(response=response, text=text)
except ValueError:
    sel = Selector(response=response) if response is not None else Selector(text=text)

Prevention

When it happens

Trigger: Selector(response=resp, text='<html>...') or Selector(resp, text=html_string); helper functions that default both parameters and forward them unconditionally; copy-pasting shell examples into code with both kwargs filled.

Common situations: Wrapping selectors in utility functions where response and text both have defaults; feeding an encoded body string alongside the response for 'safety'; interactive scrapy shell habits carried into production code.

Related errors


AI-assisted analysis of scrapy/scrapy@06af687662 (2026-08-15). Data as JSON: /api/errors/00fb92c2b21000cc. Report an issue: GitHub.