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
- Provide at least one worker: config.workers = [{ task: 'fix the failing tests', launcherCommand: 'claude "{task_file}"' }].
- Validate before calling: if (!config.workers?.length) throw new Error('at least one worker required');
- If your config builder can produce zero workers, branch around the call rather than letting buildOrchestrationPlan throw.
- 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
- Validate the workers array at config load, not inside the orchestrator call.
- Wrap single worker objects in an array before passing.
- Treat zero workers as a user-facing config error and explain how to add one.
- Default new CLI templates to a single placeholder worker so the user sees the shape.
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
- launcherCommand must be a non-empty string
- Unknown template variable: ${key}
- Seed path does not exist in repoRoot: ${seedPath}
- Worker ${index + 1} is missing a task
- Worker ${workerName} is missing a launcherCommand
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/6f0cfc59a985fa89.
Report an issue: GitHub.