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
- Use a non-negative value; 0 means no delay
- If 'disabled' was the intent, set rate_limit_delay=None or 0
- Fix RATE_LIMIT_DELAY in your .env (remove the minus sign)
- 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
- Never use negative numbers to disable the limiter — use 0 or None
- Range-check config numbers at load time and clamp to sane bounds
- Watch for stray minus signs when copying config values between environments
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
- rate_limit_delay must be a number, got {rate_limit_delay!r}
- max_tokens={max_tokens} exceeds the largest output limit of
- Invalid retriever(s) found: {', '.join(invalid_retrievers)}.
- Invalid reasoning effort: {reasoning_effort_str}. Valid opti
- RETRIEVER_ENDPOINT environment variable not set
AI-assisted analysis of assafelovic/gpt-researcher@6f998577d5 (2026-08-28).
Data as JSON: /api/errors/5395f0c735975a30.
Report an issue: GitHub.