{"record":{"id":"07da4edd29d4d03f","repo":"unclecode/crawl4ai","slug":"timeout-must-be-positive","errorCode":null,"errorMessage":"timeout must be positive","messagePattern":"timeout must be positive","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crawl4ai/async_configs.py","lineNumber":1201,"sourceCode":"            score_threshold: Minimum relevance score to include links (0.0-1.0, optional)\n            verbose: Show detailed progress during extraction\n        \"\"\"\n        self.include_internal = include_internal\n        self.include_external = include_external\n        self.include_patterns = include_patterns\n        self.exclude_patterns = exclude_patterns\n        self.concurrency = concurrency\n        self.timeout = timeout\n        self.max_links = max_links\n        self.query = query\n        self.score_threshold = score_threshold\n        self.verbose = verbose\n        \n        # Validation\n        if concurrency <= 0:\n            raise ValueError(\"concurrency must be positive\")\n        if timeout <= 0:\n            raise ValueError(\"timeout must be positive\")\n        if max_links <= 0:\n            raise ValueError(\"max_links must be positive\")\n        if score_threshold is not None and not (0.0 <= score_threshold <= 1.0):\n            raise ValueError(\"score_threshold must be between 0.0 and 1.0\")\n        if not include_internal and not include_external:\n            raise ValueError(\"At least one of include_internal or include_external must be True\")\n    \n    @staticmethod\n    def from_dict(config_dict: Dict[str, Any]) -> \"LinkPreviewConfig\":\n        \"\"\"Create LinkPreviewConfig from dictionary (for backward compatibility).\"\"\"\n        if not config_dict:\n            return None\n        \n        return LinkPreviewConfig(\n            include_internal=config_dict.get(\"include_internal\", True),\n            include_external=config_dict.get(\"include_external\", False),\n            include_patterns=config_dict.get(\"include_patterns\"),\n            exclude_patterns=config_dict.get(\"exclude_patterns\"),","sourceCodeStart":1183,"sourceCodeEnd":1219,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/async_configs.py#L1183-L1219","documentation":"LinkPreviewConfig requires a positive timeout because it is passed to per-request fetch timeouts (e.g. asyncio.wait_for). A zero or negative timeout would either fail immediately or be interpreted as no-wait, so it is rejected at construction time.","triggerScenarios":"LinkPreviewConfig(timeout=0) or a negative number; unit mismatch such as passing microseconds or 0.5 when an int number of seconds was intended via a config pipeline.","commonSituations":"Reading timeout from a JSON/YAML config where the field is missing and coerced to 0; passing timeout in the wrong unit after porting code from another library.","solutions":["Set timeout in seconds, e.g. LinkPreviewConfig(timeout=30)","Validate externally sourced values before constructing: raise/config-default if value <= 0","Do not use timeout=0 to mean 'no timeout' — this library has no such opt-out for previews"],"exampleFix":"// before\ncfg = LinkPreviewConfig(timeout=cfg_json.get(\"timeout\", 0))\n// after\ncfg = LinkPreviewConfig(timeout=cfg_json.get(\"timeout\", 30))","handlingStrategy":"validation","validationCode":"timeout = timeout if isinstance(timeout, (int, float)) and timeout > 0 else 30\ncfg = LinkPreviewConfig(timeout=timeout)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Document timeout as seconds in your config schema","Treat missing/invalid timeout as a default, not 0"],"tags":["validation","configuration","link-preview","timeout"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}