assafelovic/gpt-researcher · error · ValueError

rate_limit_delay must be a number, got {rate_limit_delay!r}

Error message

rate_limit_delay must be a number, got {rate_limit_delay!r}

What it means

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.

Source

Thrown at gpt_researcher/utils/rate_limiter.py:65

        if cls._lock is None:
            cls._lock = asyncio.Lock()
        return cls._lock

    def configure(self, rate_limit_delay: float):
        """
        Configure the global rate limit delay.

        Args:
            rate_limit_delay: Minimum seconds between requests (0 = no limit)
        """
        # Env/config may hand us strings; wait_if_needed compares as float.
        if rate_limit_delay is None:
            self.rate_limit_delay = 0.0
            return
        try:
            delay = float(rate_limit_delay)
        except (TypeError, ValueError) as e:
            raise ValueError(
                f"rate_limit_delay must be a number, got {rate_limit_delay!r}"
            ) from e
        if delay < 0:
            raise ValueError(f"rate_limit_delay must be non-negative, got {delay}")
        self.rate_limit_delay = delay

    async def wait_if_needed(self):
        """
        Wait if needed to enforce global rate limiting.

        This method ensures that regardless of how many WorkerPools are active,
        the SCRAPER_RATE_LIMIT_DELAY is respected globally.
        """
        if self.rate_limit_delay <= 0:
            return  # No rate limiting

        lock = self.get_lock()
        async with lock:

View on GitHub (pinned to 6f998577d5)

Solutions

  1. Set rate_limit_delay to a plain number or numeric string, e.g. '1.5' (seconds)
  2. Fix the env var: export RATE_LIMIT_DELAY=1.5 — no units, no commas
  3. Pass None (or omit) if you want no delay; it coerces to 0.0
  4. Add a startup check: float(os.getenv('RATE_LIMIT_DELAY', '0')) to fail fast with a clear message

Example fix

# before
os.environ['RATE_LIMIT_DELAY'] = '0.5s'
limiter = RateLimiter(0.5)  # ValueError: rate_limit_delay must be a number, got '0.5s'

# after
os.environ['RATE_LIMIT_DELAY'] = '0.5'
limiter = RateLimiter(0.5)
Defensive patterns

Strategy: validation

Validate before calling

import os
raw = os.getenv('RATE_LIMIT_DELAY', '0')
delay = float(raw)  # raises here with a clear traceback if misconfigured

Type guard

def valid_delay(v) -> bool:
    if v is None:
        return True
    try:
        return float(v) >= 0
    except (TypeError, ValueError):
        return False

Try / catch

try:
    limiter = RateLimiter(raw_delay)
except ValueError as e:
    logger.warning('Bad RATE_LIMIT_DELAY %r, defaulting to 0', raw_delay)
    limiter = RateLimiter(0)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of assafelovic/gpt-researcher@6f998577d5 (2026-08-28). Data as JSON: /api/errors/a57efadd19ae0c28. Report an issue: GitHub.