assafelovic/gpt-researcher · error · ValueError

rate_limit_delay must be non-negative, got {delay}

Error message

rate_limit_delay must be non-negative, got {delay}

What it means

RateLimiter.configure raises ValueError when rate_limit_delay parses to a float but is negative. Delays are durations, so negative values are meaningless and usually indicate a sign typo or a bad env var like RATE_LIMIT_DELAY=-1.

Source

Thrown at gpt_researcher/utils/rate_limiter.py:69

    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:
            current_time = time.time()
            time_since_last = current_time - self.last_request_time

            if time_since_last < self.rate_limit_delay:

View on GitHub (pinned to 6f998577d5)

Solutions

  1. Use a non-negative value; 0 means no delay
  2. If 'disabled' was the intent, set rate_limit_delay=None or 0
  3. Fix RATE_LIMIT_DELAY in your .env (remove the minus sign)
  4. Sanitize at startup: max(0.0, float(os.getenv('RATE_LIMIT_DELAY', 0)))

Example fix

# before
limiter = RateLimiter('-1')  # ValueError: rate_limit_delay must be non-negative, got -1.0

# after
limiter = RateLimiter('0')  # no delay
Defensive patterns

Strategy: validation

Validate before calling

import os
raw = os.getenv('RATE_LIMIT_DELAY', '0')
delay = max(0.0, float(raw))  # clamps accidental negatives

Type guard

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

Try / catch

try:
    limiter = RateLimiter(raw)
except ValueError:
    limiter = RateLimiter(0)  # safe default, log the bad value

Prevention

When it happens

Trigger: Passing rate_limit_delay=-0.5 or a string like '-1' (which float() accepts and then fails the `delay < 0` check) to RateLimiter/ configure(); often sourced from RATE_LIMIT_DELAY in env or config.

Common situations: Typo'd negative sign in an env var, attempting to use -1 as a 'disabled' sentinel, or arithmetic elsewhere in config that computed a negative delay.

Related errors


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