{"record":{"id":"bc642138a7ab7c69","repo":"unclecode/crawl4ai","slug":"setting-name-is-deprecated-self-unwanted-pr-bc6421","errorCode":null,"errorMessage":"Setting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}","messagePattern":"Setting '(.+?)' is deprecated\\. (.+?)","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"crawl4ai/async_configs.py:2055","lineNumber":1042,"sourceCode":"        \n        # Experimental Parameters\n        self.experimental = experimental or {}\n\n\n    def __getattr__(self, name):\n        \"\"\"Handle attribute access.\"\"\"\n        if name in self._UNWANTED_PROPS:\n            raise AttributeError(f\"Getting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}\")\n        raise AttributeError(f\"'{self.__class__.__name__}' has no attribute '{name}'\")\n\n    def __setattr__(self, name, value):\n        \"\"\"Handle attribute setting.\"\"\"\n        # TODO: Planning to set properties dynamically based on the __init__ signature\n        sig = inspect.signature(self.__init__)\n        all_params = sig.parameters  # Dictionary of parameter names and their details\n\n        if name in self._UNWANTED_PROPS and value is not all_params[name].default:\n            raise AttributeError(f\"Setting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}\")\n        \n        super().__setattr__(name, value)\n\n    @staticmethod\n    def from_kwargs(kwargs: dict) -> \"CrawlerRunConfig\":\n        return CrawlerRunConfig(\n            # Content Processing Parameters\n            word_count_threshold=kwargs.get(\"word_count_threshold\", 200),\n            extraction_strategy=kwargs.get(\"extraction_strategy\"),\n            chunking_strategy=kwargs.get(\"chunking_strategy\", RegexChunking()),\n            markdown_generator=kwargs.get(\"markdown_generator\"),\n            only_text=kwargs.get(\"only_text\", False),\n            css_selector=kwargs.get(\"css_selector\"),\n            target_elements=kwargs.get(\"target_elements\", []),\n            excluded_tags=kwargs.get(\"excluded_tags\", []),\n            excluded_selector=kwargs.get(\"excluded_selector\", \"\"),\n            keep_data_attributes=kwargs.get(\"keep_data_attributes\", False),\n            keep_attrs=kwargs.get(\"keep_attrs\", []),","sourceCodeStart":1024,"sourceCodeEnd":1060,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/c4ai-code-context.md#L1024-L1060","documentation":"AttributeError from CrawlerRunConfig.__setattr__: assigning to a _UNWANTED_PROPS name is rejected unless the assigned value equals the __init__ default for that parameter (which lets internal default assignment pass). The message carries the migration hint.","triggerScenarios":"config = CrawlerRunConfig(); then config.<removed prop> = value for any deprecated name with a non-default value; dynamic frameworks (dataclasses, ORMs, serializers) that setattr every field of a loaded object also trip this when the object carries a legacy key.","commonSituations":"Post-construction mutation of config with old attribute names after a version upgrade; deserializing a saved/persisted CrawlerRunConfig from an older crawl4ai; framework __setstate__-style restoration that replays legacy fields.","solutions":["Pass the option in the CrawlerRunConfig(...) constructor using its current name instead of assigning after creation","Delete stale keys before restoring persisted configs: {k: v for k, v in saved.items() if k not in DEPRECATED_NAMES}","Follow the migration hint in the error message to find the new attribute","Catch AttributeError around config restore to detect legacy payloads early and re-map them"],"exampleFix":"# before\nconfig = CrawlerRunConfig()\nconfig.old_option = True  # AttributeError: deprecated\n\n# after\nconfig = CrawlerRunConfig(new_option=True)","handlingStrategy":"validation","validationCode":"import inspect\nsig = inspect.signature(CrawlerRunConfig.__init__)\nallowed = set(sig.parameters) - set(CrawlerRunConfig._UNWANTED_PROPS)\npayload = {k: v for k, v in saved_config.items() if k in allowed}\nconfig = CrawlerRunConfig(**payload)  # construct, don't setattr","typeGuard":"def is_assignable_config_key(name: str) -> bool:\n    return name not in CrawlerRunConfig._UNWANTED_PROPS","tryCatchPattern":"try:\n    setattr(config, name, value)\nexcept AttributeError as e:\n    if \"deprecated\" in str(e):\n        new_key = MIGRATION_MAP[name]\n        config = CrawlerRunConfig(**{**asdict_like(config), new_key: value})\n    else:\n        raise","preventionTips":["Treat configs as immutable: build them via the constructor, never mutate after the fact","Strip deprecated keys when persisting/restoring configs, and pin the schema version alongside"],"tags":["crawl4ai","deprecation","config","migration"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}