{"record":{"id":"8cfec9914cbc39b0","repo":"khoj-ai/khoj","slug":"common-message-prefix-but-let-s-chat-more-next","errorCode":null,"errorMessage":"{common_message_prefix} But let's chat more {next_window}?","messagePattern":"(.+?) But let's chat more (.+?)\\?","errorType":"http","errorClass":"HTTPException","httpStatus":429,"severity":"warning","filePath":"src/khoj/routers/helpers.py","lineNumber":2182,"sourceCode":"        if not websocket.scope.get(\"user\") or not websocket.scope[\"user\"].is_authenticated:\n            return\n\n        user: KhojUser = websocket.scope[\"user\"].object\n        subscribed = has_required_scope(websocket, [\"premium\"])\n        current_window = \"today\" if self.window == 60 * 60 * 24 else \"now\"\n        next_window = \"tomorrow\" if self.window == 60 * 60 * 24 else \"in a bit\"\n        common_message_prefix = f\"I'm glad you're enjoying interacting with me! You've unfortunately exceeded your usage limit for {current_window}.\"\n\n        # Remove requests outside of the time window\n        cutoff = django_timezone.now() - timedelta(seconds=self.window)\n        count_requests = await UserRequests.objects.filter(user=user, created_at__gte=cutoff, slug=self.slug).acount()\n\n        # Check if the user has exceeded the rate limit\n        if subscribed and count_requests >= self.subscribed_requests:\n            logger.info(\n                f\"Rate limit ({self.slug}): {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for subscribed user: {user}.\"\n            )\n            raise HTTPException(\n                status_code=429,\n                detail=f\"{common_message_prefix} But let's chat more {next_window}?\",\n            )\n        if not subscribed and count_requests >= self.requests:\n            if self.requests >= self.subscribed_requests:\n                logger.info(\n                    f\"Rate limit ({self.slug}): {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for user: {user}.\"\n                )\n                raise HTTPException(\n                    status_code=429,\n                    detail=f\"{common_message_prefix} But let's chat more {next_window}?\",\n                )\n\n            logger.info(\n                f\"Rate limit ({self.slug}): {count_requests}/{self.requests} requests not allowed in {self.window} seconds for user: {user}.\"\n            )\n            raise HTTPException(\n                status_code=429,","sourceCodeStart":2164,"sourceCodeEnd":2200,"githubUrl":"https://github.com/khoj-ai/khoj/blob/ae229ca894c0b80ad84664afcfdde523b5e87057/src/khoj/routers/helpers.py#L2164-L2200","documentation":"A 429 raised in the WebSocket variant of the request rate limiter (check_websocket) when a SUBSCRIBED user exceeds the higher subscribed quota within the window. Because the user already pays, no upgrade is offered — only waiting until `next_window`.","triggerScenarios":"Opening/sending on the WebSocket chat endpoint more than `subscribed_requests` times within `self.window` seconds while authenticated as a subscribed user.","commonSituations":"Heavy programmatic WebSocket clients or agents sending bursts of messages; automated tests reusing one subscribed account; a stuck client retransmitting in a loop.","solutions":["Add exponential backoff / cooldown in the WebSocket client after a 429","Reduce message frequency or batch prompts","Verify no client-side bug is re-sending messages (check server log for the limiter slug and counts)","Wait for the window to reset (next_window hints when)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    await ws.send(frame)\nexcept (WebSocketException, HTTPException) as e:\n    if getattr(e, 'status_code', None) == 429:\n        await schedule_resend_after_window()\n    else:\n        raise","preventionTips":["Rate-limit WebSocket sends client-side below the subscribed quota","Debounce burst UI actions before sending","Monitor for 429 frames and pause the sender"],"tags":["rate-limit","http-429","websocket","khoj","subscribed"],"backgroundTag":"http-429-rate-limit-exceeded","analyzedSha":"ae229ca894c0b80ad84664afcfdde523b5e87057","analyzedAt":"2026-08-27T03:32:41.843Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}