{"record":{"id":"ce44b5bc80db95d5","repo":"nexu-io/open-design","slug":"connector-rate-limited","errorCode":"CONNECTOR_RATE_LIMITED","errorMessage":"connector tool run call limit exceeded","messagePattern":"connector tool run call limit exceeded","errorType":"http","errorClass":"ConnectorServiceError","httpStatus":429,"severity":"warning","filePath":"apps/daemon/src/connectors/service.ts","lineNumber":876,"sourceCode":"    throw new ConnectorServiceError('CONNECTOR_EXECUTION_FAILED', 'connector provider is not implemented', 501, {\n      connectorId: request.connectorId,\n      toolName: request.toolName,\n    });\n  }\n\n  private enforceRunLimits(context: ConnectorExecutionContext): void {\n    if (context.runId === undefined) return;\n\n    const now = Date.now();\n    this.pruneRunLimits(now);\n    const key = connectorRunLimitKey(context);\n    const current = this.runLimits.get(key);\n    const state: ConnectorRunLimitState = current === undefined || now - current.windowStartedAt >= CONNECTOR_RUN_RATE_LIMIT_WINDOW_MS\n      ? { windowStartedAt: now, lastSeenAt: now, windowCalls: 0, totalCalls: current?.totalCalls ?? 0 }\n      : current;\n\n    if (state.totalCalls >= CONNECTOR_RUN_TOTAL_CALL_LIMIT) {\n      throw new ConnectorServiceError('CONNECTOR_RATE_LIMITED', 'connector tool run call limit exceeded', 429, {\n        runId: context.runId ?? null,\n        totalCallLimit: CONNECTOR_RUN_TOTAL_CALL_LIMIT,\n      });\n    }\n    if (state.windowCalls >= CONNECTOR_RUN_RATE_LIMIT_CALLS) {\n      throw new ConnectorServiceError('CONNECTOR_RATE_LIMITED', 'connector tool rate limit exceeded', 429, {\n        runId: context.runId ?? null,\n        rateLimit: CONNECTOR_RUN_RATE_LIMIT_CALLS,\n        windowMs: CONNECTOR_RUN_RATE_LIMIT_WINDOW_MS,\n      });\n    }\n\n    state.windowCalls += 1;\n    state.totalCalls += 1;\n    state.lastSeenAt = now;\n    this.runLimits.set(key, state);\n  }\n","sourceCodeStart":858,"sourceCodeEnd":894,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/connectors/service.ts#L858-L894","documentation":"Thrown by ConnectorService.enforceRunLimits() with HTTP 429 when a run (context.runId) has already consumed CONNECTOR_RUN_TOTAL_CALL_LIMIT (60) connector tool calls across its entire lifetime (TTL CONNECTOR_RUN_LIMIT_TTL_MS = 15 min). It is the hard ceiling — independent of rate windows — to bound total connector spend per run. details carries runId and totalCallLimit. Calls with runId === undefined bypass enforcement entirely.","triggerScenarios":"An agent run (runId set) issues its 61st connector tool call within the 15-minute TTL window; the per-run counter (state.totalCalls) reached CONNECTOR_RUN_TOTAL_CALL_LIMIT.","commonSituations":"A long agentic loop keeps calling connector tools without termination; a tool retries in a tight loop; the run genuinely needs more connector calls than the budget allows.","solutions":["Reduce the number of connector calls in the run: cache results, batch where the tool supports it, prune no-op calls.","Start a new run if the work legitimately exceeds 60 calls — the limit is keyed per runId.","If the limit must be raised for a sanctioned workload, change CONNECTOR_RUN_TOTAL_CALL_LIMIT in apps/daemon/src/connectors/service.ts (requires a deliberate config change, not a runtime override)."],"exampleFix":"// before: calling connector tools in an unbounded loop\nwhile (!done) { await execute(req, { ...ctx, runId }); }\n\n// after: cap calls per run and hand off to a new run when exhausted\nlet calls = 0;\nwhile (!done) {\n  if (calls >= CONNECTOR_RUN_TOTAL_CALL_LIMIT) { runId = await startNewRun(); calls = 0; }\n  await execute(req, { ...ctx, runId }); calls++;\n}","handlingStrategy":"try-catch","validationCode":"// Track per-run call counts and stop before the total cap\nconst callsThisRun = runCallCounts.get(context.runId) ?? 0;\nif (context.runId !== undefined && callsThisRun >= CONNECTOR_RUN_TOTAL_CALL_LIMIT) {\n  throw new Error(`run ${context.runId} at total call limit; start a new run`);\n}\nrunCallCounts.set(context.runId, callsThisRun + 1);\nawait connectorService.execute(request, context);","typeGuard":"function runHasBudget(counts: Map<string, number>, runId: string | undefined): boolean {\n  return runId === undefined || (counts.get(runId) ?? 0) < CONNECTOR_RUN_TOTAL_CALL_LIMIT;\n}","tryCatchPattern":"try { await connectorService.execute(request, context); }\ncatch (e) {\n  if (e instanceof ConnectorServiceError && e.code === 'CONNECTOR_RATE_LIMITED' && (e.details as any)?.totalCallLimit) {\n    // start a new run (new runId) and continue, or terminate the workflow\n  } else throw e;\n}","preventionTips":["Cache connector outputs inside the run so the same call is not repeated.","Cap agent loop iterations to stay under CONNECTOR_RUN_TOTAL_CALL_LIMIT.","Surface remaining budget to the agent so it can prioritize high-value calls."],"tags":["connector","rate-limit","http-429","agent-loop"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}