ruvnet/ruflo · error · DarwinUnavailableError

Darwin archive exceeded evaluation-cost budget

Error message

Darwin archive exceeded evaluation-cost budget

What it means

proposeFlywheelCandidates sums evaluationCostMicros across all Darwin candidates and throws DarwinUnavailableError if the total exceeds safetyEnvelope.maxEvaluationCostMicros. This enforces the caller-declared evaluation spend ceiling before any candidate is evaluated downstream.

Source

Thrown at v3/@claude-flow/cli/src/services/flywheel-proposer.ts:232

        timeout = setTimeout(() => reject(new DarwinUnavailableError('Darwin exceeded wall-time budget')), maxWallTimeMs);
        timeout.unref?.();
      }),
    ]).finally(() => {
      if (timeout) clearTimeout(timeout);
    });
    if (!result.completed) {
      if (input.mode === 'darwin') throw new DarwinUnavailableError(result.reason ?? 'Darwin archive incomplete');
      return runLocal(`darwin-incomplete:${result.reason ?? 'unknown'}`);
    }
    if (result.candidates.length > (input.maxCandidates ?? 256)) {
      throw new DarwinUnavailableError('Darwin archive exceeded candidate-count budget');
    }
    const evaluationCost = result.candidates.reduce(
      (sum, candidate) => sum + candidate.resources.evaluationCostMicros,
      0,
    );
    if (evaluationCost > input.safetyEnvelope.maxEvaluationCostMicros) {
      throw new DarwinUnavailableError('Darwin archive exceeded evaluation-cost budget');
    }
    return finalizeArchive({
      requested: input.mode,
      effective: 'darwin',
      promotionAllowed: true,
      baselineRef,
      safetyEnvelope: input.safetyEnvelope,
      seed: input.seed,
      candidates: result.candidates,
      completed: true,
    });
  } catch (error) {
    if (input.mode === 'darwin') {
      if (error instanceof DarwinUnavailableError) throw error;
      throw new DarwinUnavailableError(`Darwin failed closed: ${(error as Error).message}`);
    }
    return runLocal(`darwin-error:${(error as Error).message}`);
  }

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Raise safetyEnvelope.maxEvaluationCostMicros to match the expected Darwin archive cost.
  2. Reduce the candidate count (lower maxCandidates) so the summed cost fits.
  3. Filter cheap candidates only inside the darwinInvoker wrapper before returning.
  4. Switch to mode 'auto' so a cost overrun falls back to local instead of throwing.

Example fix

// before
proposeFlywheelCandidates({ mode: 'darwin', darwinInvoker, safetyEnvelope: { maxEvaluationCostMicros: 1_000_000, ... }, ... }); // throws on cost overrun

// after — size the envelope to the archive, or trim expensive candidates
const trimmed = async (req) => {
  const r = await darwinInvoker(req);
  let cost = 0; const keep = [];
  for (const c of r.candidates) {
    if (cost + c.resources.evaluationCostMicros > req.budget.maxEvaluationCostMicros) break;
    cost += c.resources.evaluationCostMicros; keep.push(c);
  }
  return { ...r, candidates: keep };
};
proposeFlywheelCandidates({ mode: 'darwin', darwinInvoker: trimmed, ... });
Defensive patterns

Strategy: validation

Validate before calling

const safetyEnvelope = { ...input.safetyEnvelope, maxEvaluationCostMicros: Math.max(input.safetyEnvelope.maxEvaluationCostMicros, expectedArchiveCost) };
await proposeFlywheelCandidates({ mode: 'darwin', darwinInvoker, safetyEnvelope, ... });

Try / catch

try {
  return await proposeFlywheelCandidates({ mode: 'darwin', darwinInvoker, safetyEnvelope, ... });
} catch (e) {
  if (e instanceof DarwinUnavailableError && /evaluation-cost budget/.test(e.message)) {
    // raise the envelope or trim expensive candidates and retry
    return await proposeFlywheelCandidates({ mode: 'auto', darwinInvoker, safetyEnvelope: { ...safetyEnvelope, maxEvaluationCostMicros: safetyEnvelope.maxEvaluationCostMicros * 2 }, ... });
  }
  throw e;
}

Prevention

When it happens

Trigger: The combined per-candidate evaluation cost of Darwin's archive is larger than the safety envelope's maxEvaluationCostMicros — many candidates each with non-trivial evaluationCostMicros, or a few very expensive candidates.

Common situations: safetyEnvelope.maxEvaluationCostMicros set too low for the candidate volume; Darwin candidates carry high evaluationCostMicros (expensive models/large evals); the envelope was sized for the local proposer's smaller output.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/21f11173bcc60a5b. Report an issue: GitHub.