{"record":{"id":"4e4ed39b578eff11","repo":"khoj-ai/khoj","slug":"those-are-way-too-many-images-for-me-i-can-handle","errorCode":null,"errorMessage":"Those are way too many images for me! I can handle up to {self.max_images} images per message.","messagePattern":"Those are way too many images for me! I can handle up to (.+?) images per message\\.","errorType":"http","errorClass":"HTTPException","httpStatus":429,"severity":"warning","filePath":"src/khoj/routers/helpers.py","lineNumber":2228,"sourceCode":"        self.max_images = max_images\n        self.max_combined_size_mb = max_combined_size_mb\n\n    def __call__(self, request: Request, body: ChatRequestBody):\n        if state.billing_enabled is False:\n            return\n\n        # Rate limiting is disabled if user unauthenticated.\n        # Other systems handle authentication\n        if not request.user.is_authenticated:\n            return\n\n        if not body.images:\n            return\n\n        # Check number of images\n        if len(body.images) > self.max_images:\n            logger.info(f\"Rate limit: {len(body.images)}/{self.max_images} images not allowed per message.\")\n            raise HTTPException(\n                status_code=429,\n                detail=f\"Those are way too many images for me! I can handle up to {self.max_images} images per message.\",\n            )\n\n        # Check total size of images\n        total_size_mb = 0.0\n        for image in body.images:\n            # Unquote the image in case it's URL encoded\n            image = unquote(image)\n            # Assuming the image is a base64 encoded string\n            # Remove the data:image/jpeg;base64, part if present\n            if \",\" in image:\n                image = image.split(\",\", 1)[1]\n\n            # Decode base64 to get the actual size\n            image_bytes = base64.b64decode(image)\n            total_size_mb += len(image_bytes) / (1024 * 1024)  # Convert bytes to MB\n","sourceCodeStart":2210,"sourceCodeEnd":2246,"githubUrl":"https://github.com/khoj-ai/khoj/blob/ae229ca894c0b80ad84664afcfdde523b5e87057/src/khoj/routers/helpers.py#L2210-L2246","documentation":"A 429 raised by the per-message image-count limiter when a chat request body contains more images than `max_images` allows. It is a payload validation failure dressed as a rate limit, hit in the synchronous __call__ dependency of the chat endpoint.","triggerScenarios":"POSTing to /api/chat (or any endpoint using the image rate limiter) with `body.images` containing more than `self.max_images` base64 images in a single message.","commonSituations":"Clients batching whole photo albums into one message; frontend not chunking multi-image uploads; a bug concatenating image lists across messages.","solutions":["Split the request into multiple messages each with at most max_images images","Check the configured max_images value for the deployment and stay under it","Drop or downselect unnecessary images before sending","Fix client logic that accumulates images across turns"],"exampleFix":"// before\nawait client.chat({ q: prompt, images: allImages })  // 20 images\n// after\nfor (const chunk of chunkAll(allImages, 6)) {\n  await client.chat({ q: prompt, images: chunk })\n}","handlingStrategy":"validation","validationCode":"MAX_IMAGES = 6  # mirror server config\nif len(images) > MAX_IMAGES:\n    raise ValueError(f'Too many images: {len(images)} > {MAX_IMAGES}')","typeGuard":"def is_valid_image_count(images: list[str] | None, max_images: int = 6) -> bool:\n    return not images or len(images) <= max_images","tryCatchPattern":"try:\n    resp = await client.post('/api/chat', json=body)\nexcept HTTPStatusError as e:\n    if e.response.status_code == 429 and 'too many images' in e.response.text:\n        body['images'] = body['images'][:max_images]\n        resp = await client.post('/api/chat', json=body)\n    else:\n        raise","preventionTips":["Chunk images to the documented per-message limit","Validate payload size/shape before sending","Keep the limiter config in sync between client constants and server"],"tags":["rate-limit","http-429","images","payload-validation","khoj"],"backgroundTag":"request-payload-limit-exceeded","analyzedSha":"ae229ca894c0b80ad84664afcfdde523b5e87057","analyzedAt":"2026-08-27T03:32:41.843Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}