{"record":{"id":"ec3ee181aa59df5b","repo":"D4Vinci/Scrapling","slug":"response-meta-should-be-dictionary-but-got-type-m","errorCode":null,"errorMessage":"Response meta should be dictionary but got {type(meta).__name__} instead!","messagePattern":"Response meta should be dictionary but got (.+?) instead!","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"scrapling/engines/toolbelt/custom.py","lineNumber":77,"sourceCode":"\n        adaptive_domain: str = cast(str, selector_config.pop(\"adaptive_domain\", \"\"))\n        self.status = status\n        self.reason = reason\n        self.cookies = cookies\n        self.headers = headers\n        self.request_headers = request_headers\n        self.history = history or []\n        super().__init__(\n            content=content,\n            url=adaptive_domain or url,\n            encoding=encoding,\n            **selector_config,\n        )\n        # For easier debugging while working from a Python shell\n        log.info(f\"Fetched ({status}) <{method} {url}> (referer: {request_headers.get('referer')})\")\n\n        if meta and not isinstance(meta, dict):\n            raise TypeError(f\"Response meta should be dictionary but got {type(meta).__name__} instead!\")\n\n        self.meta: Dict[str, Any] = meta or {}\n        self.request: Optional[\"Request\"] = None  # Will be set by crawler\n        self.captured_xhr: List[\"Response\"] = []\n\n    @property\n    def body(self) -> bytes:\n        \"\"\"Return the raw body of the response as bytes.\"\"\"\n        return cast(bytes, cast(Sequence, self._raw_body))\n\n    def follow(\n        self,\n        url: str,\n        sid: str = \"\",\n        callback: Callable[[\"Response\"], AsyncGenerator[Union[Dict[str, Any], \"Request\", None], None]] | None = None,\n        priority: int | None = None,\n        dont_filter: bool = False,\n        meta: dict[str, Any] | None = None,","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/engines/toolbelt/custom.py#L59-L95","documentation":"Raised in the scrapling Response constructor (custom.py) when the meta argument is truthy but not a dict. Response metadata is stored as self.meta and consumed as a mapping by the crawler and follow() logic, so a non-dict truthy value (list, string, object) is rejected with a TypeError naming the actual type.","triggerScenarios":"Passing Response(..., meta=['key', 'value']) or meta='data' or meta=SomeObj(); spider callbacks constructing Response objects manually with malformed meta; passing a JSON string instead of a parsed dict.","commonSituations":"Hand-building Response objects in custom fetchers/tests; copying examples where meta was serialized (json.dumps) and forgetting to parse it back; passing a dataclass where a dict was expected.","solutions":["Pass meta as a plain dict: meta={'key': 'value'}.","If the value arrives serialized, parse it first: meta=json.loads(raw).","Omit meta entirely when you have nothing to store — it defaults to {}."],"exampleFix":"# before\nresp = Response(status, url, content, meta=json.dumps({'proxy': p}))  # TypeError: str\n\n# after\nresp = Response(status, url, content, meta={'proxy': p})","handlingStrategy":"type-guard","validationCode":"if meta is not None and not isinstance(meta, dict):\n    raise TypeError(f'meta must be dict, got {type(meta).__name__}')\nresp = Response(status, url, content, meta=meta)","typeGuard":"def is_valid_meta(meta) -> bool:\n    return meta is None or isinstance(meta, dict)","tryCatchPattern":"try:\n    resp = Response(status, url, content, meta=meta)\nexcept TypeError as e:\n    if 'meta should be dictionary' in str(e):\n        resp = Response(status, url, content)  # proceed without meta\n    else:\n        raise","preventionTips":["Type meta as Optional[Dict[str, Any]] in your own signatures.","json.loads() serialized metadata before passing it.","In tests, assert isinstance(resp.meta, dict)."],"tags":["response","validation","type-error","meta"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}