unclecode/crawl4ai · warning · AttributeError

Setting ' ' is deprecated.

Error message

Setting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}

What it means

CrawlerRunConfig.__setattr__ raises AttributeError when you assign a value to a deprecated property (listed in _UNWANTED_PROPS) that differs from its __init__ default. Assigning the default value is tolerated (for internal init), but any real attempt to set old removed settings is blocked with a pointer to the replacement.

Solutions

  1. Follow the deprecation message and set the replacement field instead
  2. Filter legacy keys before applying user config: drop keys listed in the deprecation map
  3. Temporarily pin the previous crawl4ai version if immediate migration is not feasible

Example fix

// before
cfg.old_setting = True  # removed in upgrade
// after
cfg.new_setting = True   # per deprecation message
Defensive patterns

Strategy: validation

Validate before calling

UNWANTED = set(CrawlerRunConfig._UNWANTED_PROPS)
for k in list(vars(cfg)):
    pass
# before applying external settings:
def safe_set(cfg, k, v):
    if k in CrawlerRunConfig._UNWANTED_PROPS:
        raise DeprecationWarning(f"{k} was removed; see docs")
    setattr(cfg, k, v)

Type guard

def settable(cfg, name: str) -> bool:
    return name not in CrawlerRunConfig._UNWANTED_PROPS

Try / catch

try:
    cfg.old_setting = value
except AttributeError as e:
    if "deprecated" in str(e):
        migrate_setting(cfg, old=name, new=REPLACEMENTS[name])
    else:
        raise

Prevention

When it happens

Trigger: cfg.removed_prop = value on an upgraded install; porting old scripts that configure removed options; kwargs-splatting a legacy dict onto the config object.

Common situations: Version upgrades where old settings moved to cache_mode, content_filter, or LinkPreviewConfig-style nested configs; stale user-supplied config dicts.

Related errors


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/c531d591e3ea09fb. Report an issue: GitHub.

Appendix: source

Thrown at crawl4ai/async_configs.py:2055

                return all(results) if results else False
        
        return False


    def __getattr__(self, name):
        """Handle attribute access."""
        if name in self._UNWANTED_PROPS:
            raise AttributeError(f"Getting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}")
        raise AttributeError(f"'{self.__class__.__name__}' has no attribute '{name}'")

    def __setattr__(self, name, value):
        """Handle attribute setting."""
        # TODO: Planning to set properties dynamically based on the __init__ signature
        sig = inspect.signature(self.__init__)
        all_params = sig.parameters  # Dictionary of parameter names and their details

        if name in self._UNWANTED_PROPS and value is not all_params[name].default:
            raise AttributeError(f"Setting '{name}' is deprecated. {self._UNWANTED_PROPS[name]}")
        
        super().__setattr__(name, value)

    @staticmethod
    def from_kwargs(kwargs: dict) -> "CrawlerRunConfig":
        # Auto-deserialize any dict values that use the {"type": ..., "params": ...}
        # serialization format (e.g. from JSON API requests or dump()/load() roundtrips).
        # This covers markdown_generator, extraction_strategy, content_filter, etc.
        kwargs = {
            k: from_serializable_dict(v) if isinstance(v, dict) and "type" in v else v
            for k, v in kwargs.items()
        }
        # Only pass keys present in kwargs so that __init__ defaults (and
        # set_defaults() overrides) are respected for missing keys.
        valid = inspect.signature(CrawlerRunConfig.__init__).parameters.keys() - {"self"}
        return CrawlerRunConfig(**{k: v for k, v in kwargs.items() if k in valid})

    # Create a funciton returns dict of the object

View on GitHub (pinned to 7e80152142)