{"record":{"id":"a57efadd19ae0c28","repo":"assafelovic/gpt-researcher","slug":"rate-limit-delay-must-be-a-number-got-rate-limit","errorCode":null,"errorMessage":"rate_limit_delay must be a number, got {rate_limit_delay!r}","messagePattern":"rate_limit_delay must be a number, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"gpt_researcher/utils/rate_limiter.py","lineNumber":65,"sourceCode":"        if cls._lock is None:\n            cls._lock = asyncio.Lock()\n        return cls._lock\n\n    def configure(self, rate_limit_delay: float):\n        \"\"\"\n        Configure the global rate limit delay.\n\n        Args:\n            rate_limit_delay: Minimum seconds between requests (0 = no limit)\n        \"\"\"\n        # Env/config may hand us strings; wait_if_needed compares as float.\n        if rate_limit_delay is None:\n            self.rate_limit_delay = 0.0\n            return\n        try:\n            delay = float(rate_limit_delay)\n        except (TypeError, ValueError) as e:\n            raise ValueError(\n                f\"rate_limit_delay must be a number, got {rate_limit_delay!r}\"\n            ) from e\n        if delay < 0:\n            raise ValueError(f\"rate_limit_delay must be non-negative, got {delay}\")\n        self.rate_limit_delay = delay\n\n    async def wait_if_needed(self):\n        \"\"\"\n        Wait if needed to enforce global rate limiting.\n\n        This method ensures that regardless of how many WorkerPools are active,\n        the SCRAPER_RATE_LIMIT_DELAY is respected globally.\n        \"\"\"\n        if self.rate_limit_delay <= 0:\n            return  # No rate limiting\n\n        lock = self.get_lock()\n        async with lock:","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/assafelovic/gpt-researcher/blob/6f998577d547b1e54ec662dac63583aa11e3b84b/gpt_researcher/utils/rate_limiter.py#L47-L83","documentation":"RateLimiter.configure raises ValueError when rate_limit_delay cannot be converted to a float — i.e. it's not None, not a number, and not a numeric string. This typically means a misconfigured RATE_LIMIT_DELAY env var or config value containing non-numeric text.","triggerScenarios":"Setting rate_limit_delay to a non-numeric string like '0.5s', 'half', '1,5' (comma decimal), or passing an object with no __float__; the value reaches configure() via RateLimiter __init__ from config parsing.","commonSituations":"RATE_LIMIT_DELAY env var with units ('2/sec'), localized decimal commas, quotes/whitespace artifacts, or a config file value accidentally set to a boolean/list.","solutions":["Set rate_limit_delay to a plain number or numeric string, e.g. '1.5' (seconds)","Fix the env var: export RATE_LIMIT_DELAY=1.5 — no units, no commas","Pass None (or omit) if you want no delay; it coerces to 0.0","Add a startup check: float(os.getenv('RATE_LIMIT_DELAY', '0')) to fail fast with a clear message"],"exampleFix":"# before\nos.environ['RATE_LIMIT_DELAY'] = '0.5s'\nlimiter = RateLimiter(0.5)  # ValueError: rate_limit_delay must be a number, got '0.5s'\n\n# after\nos.environ['RATE_LIMIT_DELAY'] = '0.5'\nlimiter = RateLimiter(0.5)","handlingStrategy":"validation","validationCode":"import os\nraw = os.getenv('RATE_LIMIT_DELAY', '0')\ndelay = float(raw)  # raises here with a clear traceback if misconfigured","typeGuard":"def valid_delay(v) -> bool:\n    if v is None:\n        return True\n    try:\n        return float(v) >= 0\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    limiter = RateLimiter(raw_delay)\nexcept ValueError as e:\n    logger.warning('Bad RATE_LIMIT_DELAY %r, defaulting to 0', raw_delay)\n    limiter = RateLimiter(0)","preventionTips":["Document RATE_LIMIT_DELAY as a bare number of seconds (no units, no commas)","Validate numeric env vars once at startup, not deep in library code","Use 0 or unset rather than creative sentinel values for 'disabled'"],"tags":["validation","rate-limit","configuration","env-var"],"backgroundTag":"invalid-numeric-config-value","analyzedSha":"6f998577d547b1e54ec662dac63583aa11e3b84b","analyzedAt":"2026-08-28T17:50:07.383Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}