{"record":{"id":"36b4f514df031eef","repo":"langgenius/dify","slug":"rate-limit-error-36b4f5","errorCode":"rate_limit_error","errorMessage":"Rate Limit Error","messagePattern":"Rate Limit Error","errorType":"error_code","errorClass":"InvokeRateLimitHttpError","httpStatus":429,"severity":"warning","filePath":"api/controllers/console/app/workflow.py","lineNumber":730,"sourceCode":"            args[\"external_trace_id\"] = external_trace_id\n\n        try:\n            response = AppGenerateService.generate(\n                session=session,\n                app_model=app_model,\n                user=current_user,\n                args=args,\n                invoke_from=InvokeFrom.DEBUGGER,\n                streaming=True,\n            )\n\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 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(\"/apps/<uuid:app_id>/advanced-chat/workflows/draft/iteration/nodes/<string:node_id>/run\")\nclass AdvancedChatDraftRunIterationNodeApi(Resource):\n    @console_ns.doc(\"run_advanced_chat_draft_iteration_node\")\n    @console_ns.doc(description=\"Run draft workflow iteration node for advanced chat\")\n    @console_ns.doc(params={\"app_id\": \"Application ID\", \"node_id\": \"Node ID\"})\n    @console_ns.expect(console_ns.models[IterationNodeRunPayload.__name__])\n    @console_ns.response(\n        200,\n        \"Iteration node run started successfully\",\n        console_ns.models[GeneratedAppResponse.__name__],\n    )","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/workflow.py#L712-L748","documentation":"Raised as InvokeRateLimitHttpError (HTTP 400, code 'rate_limit_error') from the AdvancedChatDraftWorkflowRunApi.post handler at POST /apps/{app_id}/advanced-chat/workflows/draft/run when AppGenerateService.generate triggers the per-tenant/per-app rate limiter during an advanced-chat draft debug run. The underlying core.error.InvokeRateLimitError carries a description string that is forwarded verbatim to the HTTP error. It signals the debug-run invocation exceeded the configured invocation quota, not a model provider 429.","triggerScenarios":"Issuing repeated POST /apps/{app_id}/advanced-chat/workflows/draft/run (streaming debugger) faster than the workspace's rate-limit window allows; the limiter trips inside AppGenerateService.generate before the SSE stream is returned.","commonSituations":"Auto-retry loops in the workflow debugger, a stuck frontend re-firing the run on error, shared dev tenant hammered by several developers, or rate-limit config (e.g. dify_config invocation quotas) set too low for the workload.","solutions":["Back off and retry the same draft run after the limiter window elapses; the response description states the wait.","Check the rate-limit configuration for the workspace/tenant and raise the cap if the legitimate debug load needs it.","Stop duplicate concurrent run requests from the client (debounce the run button, cancel in-flight requests).","Inspect server logs to confirm the limiter key (tenant/app/user) and identify which caller is saturating it."],"exampleFix":"// before: client retries immediately on any error\nasync function runDraft() {\n  await fetch(`/apps/${appId}/advanced-chat/workflows/draft/run`, {method:'POST', body});\n}\n// after: honor Retry-After / back off on rate_limit_error\nasync function runDraft() {\n  const r = await fetch(url, {method:'POST', body});\n  if (r.status === 400 && (await r.json()).code === 'rate_limit_error') {\n    await sleep(backoffMs()); return;\n  }\n}","handlingStrategy":"retry","validationCode":"// Before the call, gate on a client-side token bucket sized to the known workspace limit.\nconst bucket = makeTokenBucket({capacity: RATE_LIMIT, refillPerSec: REFILL});\nasync function safeDraftRun(appId, body) {\n  if (!bucket.tryConsume(1)) {\n    return {skip: true, retryInMs: bucket.timeUntilNext()};\n  }\n  return fetch(`/console/apps/${appId}/advanced-chat/workflows/draft/run`, {method:'POST', body: JSON.stringify(body)});\n}","typeGuard":null,"tryCatchPattern":"// Honor the rate-limit description / back off; surface to UI as throttled.\ntry {\n  return await runDraftRun(appId, body);\n} catch (e) {\n  if (isHttpError(e, 400, 'rate_limit_error')) {\n    scheduleRetry(e.description); // parse wait from description\n    return;\n  }\n  throw e;\n}","preventionTips":["Debounce the debug-run button and cancel in-flight requests.","Track the rate-limit window client-side and disable the run button while cooling down.","Coordinate shared-tenant load with team members during heavy debugging."],"tags":["rate-limit","workflow","advanced-chat","debugger","console-api"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}