{"record":{"id":"57ec48667723fa94","repo":"langgenius/dify","slug":"rate-limit-error-57ec48","errorCode":"rate_limit_error","errorMessage":"Rate Limit Error","messagePattern":"Rate Limit Error","errorType":"console","errorClass":"InvokeRateLimitHttpError","httpStatus":429,"severity":"warning","filePath":"api/controllers/console/explore/completion.py","lineNumber":235,"sourceCode":"            # response-contract:ignore compact_generate_response\n            return helper.compact_generate_response(response)\n        except services.errors.conversation.ConversationNotExistsError:\n            raise NotFound(\"Conversation Not Exists.\")\n        except services.errors.conversation.ConversationCompletedError:\n            raise ConversationCompletedError()\n        except services.errors.app_model_config.AppModelConfigBrokenError:\n            logger.exception(\"App model config broken.\")\n            raise AppUnavailableError()\n        except ProviderTokenNotInitError as ex:\n            raise ProviderNotInitializeError(ex.description)\n        except QuotaExceededError:\n            raise ProviderQuotaExceededError()\n        except ModelCurrentlyNotSupportError:\n            raise ProviderModelCurrentlyNotSupportError()\n        except InvokeError as e:\n            raise CompletionRequestError(e.description)\n        except InvokeRateLimitError as ex:\n            raise InvokeRateLimitHttpError(ex.description)\n        except ValueError as e:\n            raise e\n        except Exception:\n            logger.exception(\"internal server error.\")\n            raise InternalServerError()\n\n\n@console_ns.route(\n    \"/installed-apps/<uuid:installed_app_id>/chat-messages/<string:task_id>/stop\",\n    endpoint=\"installed_app_stop_chat_completion\",\n)\nclass ChatStopApi(InstalledAppResource):\n    @console_ns.response(200, \"Success\", console_ns.models[SimpleResultResponse.__name__])\n    @with_current_user_id\n    @with_session(write=False)\n    def post(self, session: Session, current_user_id: str, installed_app: InstalledApp, task_id: str):\n        app_model = installed_app.app_with_session(session=session)\n        if app_model is None:","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/explore/completion.py#L217-L253","documentation":"InvokeRateLimitHttpError (HTTP 429, code 'rate_limit_error') is raised in ChatApi.post when AppGenerateService.generate throws services.errors.llm.InvokeRateLimitError. This specifically indicates the model provider returned a rate-limit response (e.g. OpenAI HTTP 429 'Too Many Requests') during a chat-completion call on an installed Explore app. It is caught separately from the generic InvokeError so callers can implement backoff.","triggerScenarios":"POST /console/explore/installed-apps/<installed_app_id>/chat-messages sent at a frequency exceeding the model provider's rate limit (RPM/TPM), or when a shared provider key is being consumed by many concurrent users/tenants simultaneously.","commonSituations":"Multiple installed apps share the same provider key and collectively exceed the key's RPM; a burst of chat messages from the same tenant; the provider plan tier has a low RPM cap; automated test or load-test scripts hammering the endpoint without throttling.","solutions":["Implement client-side exponential backoff with jitter and retry after a brief wait (the error is transient by nature).","Reduce the request rate — add client-side throttling or a queue to stay under the provider's documented RPM/TPM limits.","Upgrade the provider API plan to a higher rate-limit tier, or configure a dedicated provider key for high-traffic apps.","Check Settings → Model Provider for the specific provider's rate-limit details and consider spreading load across multiple providers."],"exampleFix":"// before: fire requests in a tight loop\nfor (const q of queries) { await post('/chat-messages', {query: q}); }\n// after: retry with backoff on 429\nasync function chatWithRetry(payload, retries=5) {\n  for (let i=0; i<retries; i++) {\n    const res = await post('/chat-messages', payload);\n    if (res.status !== 429) return res;\n    await sleep(Math.min(1000*2**i, 30000) + Math.random()*500);\n  }\n  throw new Error('Rate limit exceeded after retries');\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function chatWithBackoff(installedAppId, payload, maxRetries = 5) {\n  for (let attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n      return await postChatMessage(installedAppId, payload);\n    } catch (e) {\n      if (e.code === 'rate_limit_error' && attempt < maxRetries) {\n        const delay = Math.min(1000 * 2 ** attempt, 30000) + Math.random() * 500;\n        await new Promise(r => setTimeout(r, delay));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Implement client-side rate limiting to stay under the provider's RPM/TPM caps.","Use exponential backoff with jitter for 429 responses — never retry immediately.","If rate limits are hit consistently, upgrade the provider plan or use a dedicated key for the installed app."],"tags":["rate-limit","llm-provider","chat-completion","retryable","installed-app"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}