{"record":{"id":"588fac756fa4fd11","repo":"D4Vinci/Scrapling","slug":"self-class-name-must-have-a-name","errorCode":null,"errorMessage":"{self.__class__.__name__} must have a name.","messagePattern":"(.+?) must have a name\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scrapling/spiders/spider.py","lineNumber":113,"sourceCode":"    # Fingerprint adjustments\n    fp_include_kwargs: bool = False\n    fp_keep_fragments: bool = False\n    fp_include_headers: bool = False\n\n    # Logging settings\n    logging_level: int = logging.DEBUG\n    logging_format: str = \"[%(asctime)s]:({spider_name}) %(levelname)s: %(message)s\"\n    logging_date_format: str = \"%Y-%m-%d %H:%M:%S\"\n    log_file: Optional[str] = None\n\n    def __init__(self, crawldir: Optional[Union[str, Path, AsyncPath]] = None, interval: float = 300.0):\n        \"\"\"Initialize the spider.\n\n        :param crawldir: Directory for checkpoint files. If provided, enables pause/resume.\n        :param interval: Seconds between periodic checkpoint saves (default 5 minutes).\n        \"\"\"\n        if self.name is None:\n            raise ValueError(f\"{self.__class__.__name__} must have a name.\")\n\n        self.logger = logging.getLogger(f\"scrapling.spiders.{self.name}\")\n        self.logger.setLevel(self.logging_level)\n        self.logger.handlers.clear()\n        self.logger.propagate = False  # Don't propagate to parent 'scrapling' logger\n\n        formatter = logging.Formatter(\n            fmt=self.logging_format.format(spider_name=self.name), datefmt=self.logging_date_format\n        )\n\n        # Add a log counter handler to track log counts by level\n        self._log_counter = LogCounterHandler()\n        self.logger.addHandler(self._log_counter)\n\n        console_handler = logging.StreamHandler()\n        console_handler.setFormatter(formatter)\n        self.logger.addHandler(console_handler)\n","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/spiders/spider.py#L95-L131","documentation":"Spider.__init__ requires a non-None name class attribute. The name is used for the logger ('scrapling.spiders.<name>') and log formatting, so an anonymous spider cannot be initialized.","triggerScenarios":"Defining a Spider subclass without setting `name = \"...\"` as a class attribute (the base class declares name = None); instantiating the abstract Spider base class directly.","commonSituations":"Following tutorials for non-scrapling frameworks that don't require names; creating quick test spiders and forgetting the attribute; copying a class and deleting fields while refactoring.","solutions":["Add a unique class attribute: name = \"my_spider\" on the subclass","Give each spider a distinct name so per-spider loggers don't collide"],"exampleFix":"// before\nclass MySpider(Spider):\n    start_urls = [\"https://example.com\"]\n\n// after\nclass MySpider(Spider):\n    name = \"my_spider\"\n    start_urls = [\"https://example.com\"]","handlingStrategy":"validation","validationCode":"class MySpider(Spider):\n    name = \"my_spider\"  # required class attribute\n\nassert MySpider.name, \"spider must define a name\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set name as the first attribute of every spider class","Add a startup check/test that instantiates each spider class to catch missing names early"],"tags":["spider","configuration","validation"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}