{"record":{"id":"8e40b3742865047f","repo":"Mintplex-Labs/anything-llm","slug":"rate-limit-exceeded","errorCode":null,"errorMessage":"Rate limit exceeded","messagePattern":"Rate limit exceeded","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"server/utils/middleware/embedMiddleware.js","lineNumber":137,"sourceCode":"          ? \"Message is empty.\"\n          : `${embed.chat_mode} is not a valid mode.`,\n      });\n      return;\n    }\n\n    if (\n      !isNaN(embed.max_chats_per_day) &&\n      Number(embed.max_chats_per_day) > 0\n    ) {\n      const dailyChatCount = await EmbedChats.count({\n        embed_id: embed.id,\n        createdAt: {\n          gte: new Date(new Date() - 24 * 60 * 60 * 1000),\n        },\n      });\n\n      if (dailyChatCount >= Number(embed.max_chats_per_day)) {\n        response.status(429).json({\n          id: uuidv4(),\n          type: \"abort\",\n          textResponse: null,\n          sources: [],\n          close: true,\n          error: \"Rate limit exceeded\",\n          errorMsg:\n            \"The quota for this chat has been reached. Try again later or contact the site owner.\",\n        });\n        return;\n      }\n    }\n\n    if (\n      !isNaN(embed.max_chats_per_session) &&\n      Number(embed.max_chats_per_session) > 0\n    ) {\n      const dailySessionCount = await EmbedChats.count({","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/utils/middleware/embedMiddleware.js#L119-L155","documentation":"Daily quota enforcement inside canRespond: when the embed has max_chats_per_day > 0 and the count of EmbedChats rows for that embed in the last 24 hours has reached it, the request gets HTTP 429 with a structured abort payload whose error field is 'Rate limit exceeded'. The window is rolling (createdAt >= now-24h), counted across ALL sessions on the embed.","triggerScenarios":"Popular embed hitting its configured daily cap: any message once count >= max_chats_per_day returns 429 until enough old chats age out of the 24h window. Triggered by real traffic, shared scraping of a public embed, or a low cap set during testing.","commonSituations":"Demo embed left with max_chats_per_day=5 hitting the cap immediately; bot traffic burning the quota; admin forgot the cap was set on production embeds.","solutions":["Raise or clear max_chats_per_day on the embed config (blank/0 disables the quota), then messages resume immediately","Wait for chats to fall out of the rolling 24h window — no fixed midnight reset exists","Widget side: on 429 with type:'abort' and close:true, stop retrying; the window is hours, not seconds"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// owner-side: keep quota sane so real users don't hit it mid-conversation\nif (!Number.isFinite(Number(embed.max_chats_per_day)) || Number(embed.max_chats_per_day) < 1)\n  console.info('Daily quota disabled for embed', embed.uuid);","typeGuard":null,"tryCatchPattern":"if (res.status === 429) {\n  const data = await res.json();\n  if (data.error === 'Rate limit exceeded') {\n    showQuotaNotice(data.errorMsg); // visitor-friendly text ships in errorMsg\n    scheduleRetryAfterRollingWindow(); // 24h rolling window — do NOT tight-loop\n  }\n}","preventionTips":["Set max_chats_per_day from expected traffic, not a leftover test value","Treat 429 + type:'abort' + close:true as terminal for the current visit","Alert admins when an embed's daily denial rate spikes (bot traffic)"],"tags":["embed","rate-limit","quota","http-429","anythingllm"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}