{"record":{"id":"e59ff82a3e995b9d","repo":"run-llama/llama_index","slug":"at-least-one-of-requests-per-minute-or-tokens-per","errorCode":null,"errorMessage":"At least one of requests_per_minute or tokens_per_minute must be set.","messagePattern":"At least one of requests_per_minute or tokens_per_minute must be set\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/rate_limiter.py","lineNumber":291,"sourceCode":"        gt=0,\n    )\n    token_burst: float = Field(\n        default=0.0,\n        ge=0.0,\n        description=(\n            \"Additional tokens allowed as burst capacity within the sliding window. \"\n            \"Set to 0 for a strict cap.\"\n        ),\n    )\n\n    _request_timestamps: Deque[float] = PrivateAttr(default_factory=deque)\n    _token_usage: Deque[Tuple[float, float]] = PrivateAttr(default_factory=deque)\n    _lock: threading.Lock = PrivateAttr(default_factory=threading.Lock)\n\n    @model_validator(mode=\"after\")\n    def _check_limits(self) -> \"SlidingWindowRateLimiter\":\n        if self.requests_per_minute is None and self.tokens_per_minute is None:\n            raise ValueError(\n                \"At least one of requests_per_minute or tokens_per_minute must be set.\"\n            )\n        return self\n\n    def _prune_request_timestamps(self, now: float) -> None:\n        \"\"\"Remove request timestamps outside the sliding window. Hold _lock.\"\"\"\n        while (\n            self._request_timestamps\n            and self._request_timestamps[0] < now - _SLIDING_WINDOW_SECONDS\n        ):\n            self._request_timestamps.popleft()\n\n    def _prune_token_usage(self, now: float) -> None:\n        \"\"\"Remove token usage entries outside the sliding window. Hold _lock.\"\"\"\n        while (\n            self._token_usage\n            and self._token_usage[0][0] < now - _SLIDING_WINDOW_SECONDS\n        ):","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/rate_limiter.py#L273-L309","documentation":"SlidingWindowRateLimiter is a pydantic model whose model_validator(mode='after') enforces that at least one limit is configured: requests_per_minute or tokens_per_minute. Creating one with both None raises ValueError, since a limiter with no cap is meaningless.","triggerScenarios":"SlidingWindowRateLimiter() with no arguments, or explicitly passing requests_per_minute=None, tokens_per_minute=None (e.g. forwarding unset config values from env/CLI where missing settings become None).","commonSituations":"Building the limiter from optional config (os.getenv returning None) and passing both unset values through; instantiating to inspect defaults before deciding limits.","solutions":["Set at least one limit, e.g. SlidingWindowRateLimiter(requests_per_minute=60)","When loading from config, apply defaults for missing values before construction: rpm or 60, tpm or 100_000","Validate configuration early (fail fast at startup) rather than deep inside a query run"],"exampleFix":"// before\nrpm = os.getenv(\"RATE_LIMIT_RPM\")  # may be None\ntpm = os.getenv(\"RATE_LIMIT_TPM\")  # may be None\nlimiter = SlidingWindowRateLimiter(requests_per_minute=rpm, tokens_per_minute=tpm)\n\n// after\nrpm = os.getenv(\"RATE_LIMIT_RPM\")\ntpm = os.getenv(\"RATE_LIMIT_TPM\")\nif rpm is None and tpm is None:\n    raise SystemExit(\"Configure RATE_LIMIT_RPM or RATE_LIMIT_TPM\")\nlimiter = SlidingWindowRateLimiter(\n    requests_per_minute=float(rpm) if rpm else None,\n    tokens_per_minute=float(tpm) if tpm else None,\n)","handlingStrategy":"validation","validationCode":"def build_limiter(rpm, tpm):\n    if rpm is None and tpm is None:\n        raise ValueError(\"Configure RATE_LIMIT_RPM or RATE_LIMIT_TPM before startup\")\n    return SlidingWindowRateLimiter(\n        requests_per_minute=float(rpm) if rpm is not None else None,\n        tokens_per_minute=float(tpm) if tpm is not None else None,\n    )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fail fast on config: validate rate-limit settings at process start, not mid-query","Give optional env-backed settings explicit defaults (e.g. rpm=60) when the variable is missing","Never construct the limiter with both limits None from forwarded optional values"],"tags":["rate-limit","config","validation","constructor"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}