affaan-m/ECC · error

buildOrchestrationPlan requires at least one worker

Error message

buildOrchestrationPlan requires at least one worker

What it means

Thrown by buildOrchestrationPlan() when config.workers is missing, not an array, or an empty array. The orchestrator's whole purpose is to fan out work across multiple tmux panes with one worker per pane, so a workerless plan has no effect and would produce a session with only the orchestrator pane. The check fires before any per-worker validation.

Source

Thrown at scripts/lib/tmux-worktree-orchestrator.js:190

  };
}

function buildOrchestrationPlan(config = {}) {
  const repoRoot = path.resolve(config.repoRoot || process.cwd());
  const repoName = path.basename(repoRoot);
  const workers = Array.isArray(config.workers) ? config.workers : [];
  const globalSeedPaths = normalizeSeedPaths(config.seedPaths, repoRoot);
  const sessionName = slugify(config.sessionName || repoName, 'session');
  const worktreeRoot = path.resolve(config.worktreeRoot || path.dirname(repoRoot));
  const coordinationRoot = path.resolve(
    config.coordinationRoot || path.join(repoRoot, '.orchestration')
  );
  const coordinationDir = path.join(coordinationRoot, sessionName);
  const baseRef = config.baseRef || 'HEAD';
  const defaultLauncher = config.launcherCommand || '';

  if (workers.length === 0) {
    throw new Error('buildOrchestrationPlan requires at least one worker');
  }

  const seenSlugs = new Set();
  const workerPlans = workers.map((worker, index) => {
    if (!worker || typeof worker.task !== 'string' || worker.task.trim().length === 0) {
      throw new Error(`Worker ${index + 1} is missing a task`);
    }

    const workerName = worker.name || `worker-${index + 1}`;
    const workerSlug = slugify(workerName, `worker-${index + 1}`);

    if (seenSlugs.has(workerSlug)) {
      throw new Error(`Workers must have unique slugs — duplicate: ${workerSlug}`);
    }
    seenSlugs.add(workerSlug);

    const branchName = `orchestrator-${sessionName}-${workerSlug}`;
    const worktreePath = path.join(worktreeRoot, `${repoName}-${sessionName}-${workerSlug}`);

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Provide at least one worker: config.workers = [{ task: 'fix the failing tests', launcherCommand: 'claude "{task_file}"' }].
  2. Validate before calling: if (!config.workers?.length) throw new Error('at least one worker required');
  3. If your config builder can produce zero workers, branch around the call rather than letting buildOrchestrationPlan throw.
  4. Wrap a single worker in an array rather than passing it bare.

Example fix

// before
buildOrchestrationPlan({ repoRoot, launcherCommand, workers: [] });
// -> buildOrchestrationPlan requires at least one worker

// after
buildOrchestrationPlan({
  repoRoot,
  launcherCommand: 'claude "{task_file}"',
  workers: [{ task: 'fix the failing tests' }],
});
Defensive patterns

Strategy: validation

Validate before calling

function assertWorkers(config) {
  if (!Array.isArray(config.workers) || config.workers.length === 0) {
    throw new Error('Orchestration requires at least one worker');
  }
}

assertWorkers(config);
buildOrchestrationPlan(config);

Type guard

function hasWorkers(config) {
  return !!config && Array.isArray(config.workers) && config.workers.length > 0;
}

Try / catch

try {
  buildOrchestrationPlan(config);
} catch (error) {
  if (/requires at least one worker/.test(error.message)) {
    // nothing to do — surface a friendly message to the user
    console.error('Add at least one worker to your orchestrator config.');
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling buildOrchestrationPlan({ repoRoot }) with no workers key; config.workers = [] ; config.workers = undefined (Array.isArray returns false, defaulting to []); config.workers = null; passing a single worker object instead of an array.

Common situations: A CLI default of workers: [] that the user never populates; a config template shipped with an empty workers array as a placeholder; programmatic use that builds the workers list conditionally and the condition is false; misreading the API and passing one worker object directly.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/6f0cfc59a985fa89. Report an issue: GitHub.