khoj-ai/khoj · warning · HTTPException

{common_message_prefix} But let's chat more {next_window}?

Error message

{common_message_prefix} But let's chat more {next_window}?

What it means

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`.

Source

Thrown at src/khoj/routers/helpers.py:2182

        if not websocket.scope.get("user") or not websocket.scope["user"].is_authenticated:
            return

        user: KhojUser = websocket.scope["user"].object
        subscribed = has_required_scope(websocket, ["premium"])
        current_window = "today" if self.window == 60 * 60 * 24 else "now"
        next_window = "tomorrow" if self.window == 60 * 60 * 24 else "in a bit"
        common_message_prefix = f"I'm glad you're enjoying interacting with me! You've unfortunately exceeded your usage limit for {current_window}."

        # Remove requests outside of the time window
        cutoff = django_timezone.now() - timedelta(seconds=self.window)
        count_requests = await UserRequests.objects.filter(user=user, created_at__gte=cutoff, slug=self.slug).acount()

        # Check if the user has exceeded the rate limit
        if subscribed and count_requests >= self.subscribed_requests:
            logger.info(
                f"Rate limit ({self.slug}): {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for subscribed user: {user}."
            )
            raise HTTPException(
                status_code=429,
                detail=f"{common_message_prefix} But let's chat more {next_window}?",
            )
        if not subscribed and count_requests >= self.requests:
            if self.requests >= self.subscribed_requests:
                logger.info(
                    f"Rate limit ({self.slug}): {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for user: {user}."
                )
                raise HTTPException(
                    status_code=429,
                    detail=f"{common_message_prefix} But let's chat more {next_window}?",
                )

            logger.info(
                f"Rate limit ({self.slug}): {count_requests}/{self.requests} requests not allowed in {self.window} seconds for user: {user}."
            )
            raise HTTPException(
                status_code=429,

View on GitHub (pinned to ae229ca894)

Solutions

  1. Add exponential backoff / cooldown in the WebSocket client after a 429
  2. Reduce message frequency or batch prompts
  3. Verify no client-side bug is re-sending messages (check server log for the limiter slug and counts)
  4. Wait for the window to reset (next_window hints when)
Defensive patterns

Strategy: retry

Try / catch

try:
    await ws.send(frame)
except (WebSocketException, HTTPException) as e:
    if getattr(e, 'status_code', None) == 429:
        await schedule_resend_after_window()
    else:
        raise

Prevention

When it happens

Trigger: Opening/sending on the WebSocket chat endpoint more than `subscribed_requests` times within `self.window` seconds while authenticated as a subscribed user.

Common situations: Heavy programmatic WebSocket clients or agents sending bursts of messages; automated tests reusing one subscribed account; a stuck client retransmitting in a loop.

Related errors


AI-assisted analysis of khoj-ai/khoj@ae229ca894 (2026-08-27). Data as JSON: /api/errors/8cfec9914cbc39b0. Report an issue: GitHub.