ruvnet/ruflo · error
Hourly cost limit exceeded: $${this.hourlyCost.amount.toFixe
Error message
Hourly cost limit exceeded: $${this.hourlyCost.amount.toFixed(2)} / $${this.config.costLimitPerHour} What it means
ProviderAdapter tracks accumulated spend in a rolling hour (hourlyCost); once the amount reaches config.costLimitPerHour, checkCostLimits refuses every further execution until the window resets (resetAt = last reset + 3600000ms). It is a hard cost circuit-breaker, not a warning.
Source
Thrown at v3/@claude-flow/integration/src/provider-adapter.ts:943
if (provider.status === 'rate-limited') {
throw new Error(`Provider ${provider.id} is rate limited`);
}
}
/**
* Check cost limits
*/
private checkCostLimits(): void {
const now = Date.now();
// Reset hourly cost if needed
if (now >= this.hourlyCost.resetAt) {
this.hourlyCost.amount = 0;
this.hourlyCost.resetAt = now + 3600000;
}
if (this.hourlyCost.amount >= this.config.costLimitPerHour!) {
throw new Error(
`Hourly cost limit exceeded: $${this.hourlyCost.amount.toFixed(2)} / $${this.config.costLimitPerHour}`
);
}
}
/**
* Get cached result
*/
private getCachedResult(
task: Task,
providerId: string
): ExecutionResult | null {
const cacheKey = `${providerId}:${task.id}:${task.description}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.config.cacheTTL!) {
this.emit('cache-hit', { taskId: task.id, providerId });
return cached.result;View on GitHub (pinned to fa13ee4ad6)
Solutions
- If the budget genuinely allows, raise config.costLimitPerHour
- Otherwise wait for the hourly window to reset (up to 1h from the last reset)
- Route to cheaper providers/models or reduce token usage per task so hourly burn stays under the cap
- Track spend upstream and throttle submissions before the adapter's breaker trips
Example fix
// before
const adapter = new ProviderAdapterManager({ costLimitPerHour: 1 }); // trips minutes into a bulk run
// after
const adapter = new ProviderAdapterManager({ costLimitPerHour: 25 }); // sized to measured hourly burn Defensive patterns
Strategy: validation
Validate before calling
// Mirror the adapter's rolling-hour accounting so you stop before it does
const spend = { amount: 0, resetAt: Date.now() + 3600_000 };
function canAfford(estimatedCost: number, cap: number): boolean {
if (Date.now() >= spend.resetAt) {
spend.amount = 0;
spend.resetAt = Date.now() + 3600_000;
}
return spend.amount + estimatedCost < cap * 0.9; // 10% headroom
} Try / catch
try {
await adapter.execute(task);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Hourly cost limit exceeded')) {
// pause the queue until the hour resets; do not create new adapter instances to dodge the cap
}
throw e;
} Prevention
- Estimate per-task cost and enforce your own 90% threshold before submission
- Alert when hourly spend crosses 50%/80% of the cap
- Treat tripping the breaker as a budgeting bug, not a runtime fault to retry
When it happens
Trigger: Any execution path that runs checkCostLimits after this hour's tracked spend has reached costLimitPerHour — the very next call throws, regardless of how cheap the target provider is.
Common situations: costLimitPerHour set below the workload's real burn rate (e.g. a $1 cap with token-heavy models), an expensive model selected for bulk jobs, or many workers sharing a single adapter instance and therefore one hourly budget.
Related errors
- budgetUsdMonthly must be ≥0
- budgetUsdPerRun must be ≥0
- pod-template at /: budgetUsdPerRun must not exceed budgetUsd
- Pool ${this.id} at maximum capacity (${this.config.maxWorker
- Invalid completion type
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/68db5a876df1b587.
Report an issue: GitHub.