{"record":{"id":"3bbe92df8dcd3c61","repo":"PrefectHQ/fastmcp","slug":"rate-limit-exceeded-for-client-client-id","errorCode":null,"errorMessage":"Rate limit exceeded for client: {client_id}","messagePattern":"Rate limit exceeded for client: (.+?)","errorType":"exception","errorClass":"RateLimitError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/middleware/rate_limiting.py","lineNumber":171,"sourceCode":"            if inspect.isawaitable(client_id):\n                return cast(str, await client_id)\n            return client_id\n        return \"global\"\n\n    async def on_request(self, context: MiddlewareContext, call_next: CallNext) -> Any:\n        \"\"\"Apply rate limiting to requests.\"\"\"\n        if self.global_limit:\n            # Global rate limiting\n            allowed = await self.global_limiter.consume()\n            if not allowed:\n                raise RateLimitError(\"Global rate limit exceeded\")\n        else:\n            # Per-client rate limiting\n            client_id = await self._get_client_identifier(context)\n            limiter = self.limiters[client_id]\n            allowed = await limiter.consume()\n            if not allowed:\n                raise RateLimitError(f\"Rate limit exceeded for client: {client_id}\")\n\n        return await call_next(context)\n\n\nclass SlidingWindowRateLimitingMiddleware(Middleware):\n    \"\"\"Middleware that implements sliding window rate limiting.\n\n    Uses a sliding window approach which provides more precise rate limiting\n    but uses more memory to track individual request timestamps.\n\n    Example:\n        ```python\n        from fastmcp.server.middleware.rate_limiting import SlidingWindowRateLimitingMiddleware\n\n        # Allow 100 requests per minute\n        rate_limiter = SlidingWindowRateLimitingMiddleware(\n            max_requests=100,\n            window_minutes=1","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/middleware/rate_limiting.py#L153-L189","documentation":"Raised as RateLimitError by RateLimitingMiddleware.on_request when per-client mode is active and the specific client identified by _get_client_identifier exhausts its token-bucket allowance. Only that client is throttled; other clients are unaffected.","triggerScenarios":"RateLimitingMiddleware configured with global_limit=False (per-client mode); a single client_id exceeds max_requests within window_seconds; limiter.consume() returns False for that client's bucket.","commonSituations":"A runaway script or retry loop hammering the server from one identity; many users behind one proxy so they share one client_id and hit the cap collectively; per-client limits copied from global-appropriate numbers.","solutions":["Back off and retry client-side with exponential backoff inside the window.","Raise max_requests/window_seconds if the limit is mis-sized for a legitimate client.","If many users share one IP/client_id, improve client identification (e.g. per-auth-token identity) so limits are per real user."],"exampleFix":"// before: tight retry loop\nfor attempt in range(1000):\n    await client.call_tool(\"process\", {\"id\": attempt})\n\n// after: respect the rate limit\nfor attempt in range(1000):\n    try:\n        await client.call_tool(\"process\", {\"id\": attempt})\n    except RateLimitError:\n        await anyio.sleep(5)\n        await client.call_tool(\"process\", {\"id\": attempt})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import anyio, random\nfor attempt in range(5):\n    try:\n        result = await client.call_tool(name, args)\n        break\n    except Exception as e:\n        if f\"Rate limit exceeded for client\" in str(e) and attempt < 4:\n            await anyio.sleep(random.uniform(1, 5) * 2 ** attempt)\n            continue\n        raise","preventionTips":["Add client-side pacing/throttling below the server's per-client cap.","Use exponential backoff with jitter on 429-style RateLimitError.","Avoid retry loops without delays that re-trigger the same limiter.","If many users share one client_id (proxy/NAT), switch identity source or raise the per-client cap."],"tags":["rate-limiting","middleware","clients"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}