affaan-m/ECC · error · Error
buildOrchestrationPlan requires at least one worker
Error message
buildOrchestrationPlan requires at least one worker
What it means
buildOrchestrationPlan assembles the per-worker tmux worktree plan and requires at least one worker in the config. It throws when the workers array is empty, since a plan with no workers would create nothing and mislead the caller into thinking orchestration succeeded.
Solutions
- Add at least one worker object with a non-empty task to config.workers.
- Fix the upstream filter/selection so at least one worker survives.
- Check the config file/loader to ensure the workers array is actually populated.
- Guard the caller: validate workers.length > 0 and report a friendly config error before invoking the planner.
Example fix
// before
buildOrchestrationPlan({ sessionName: 's1', workers: [] });
// after
buildOrchestrationPlan({ sessionName: 's1', workers: [{ task: 'run tests' }] }); Defensive patterns
Strategy: validation
Validate before calling
if (!Array.isArray(config.workers) || config.workers.length === 0) {
throw new Error('Orchestration config must define at least one worker');
} Type guard
const hasWorkers = (c) => Array.isArray(c?.workers) && c.workers.length > 0;
Try / catch
try {
const plan = buildOrchestrationPlan(config);
} catch (e) {
if (String(e.message) === 'buildOrchestrationPlan requires at least one worker') {
console.error('No workers defined; check config.workers and any filters');
}
throw e;
} Prevention
- Validate config.workers is a non-empty array at load time.
- Audit any worker filters to ensure they cannot produce an empty set.
- Provide example configs with at least one worker.
- Add a unit test for the empty-workers config case.
When it happens
Trigger: Calling buildOrchestrationPlan(config) (or the plan() wrapper) with config.workers === [], workers omitted but defaulted to [], or an upstream filter step that removed all workers.
Common situations: Empty 'workers' section in the orchestration config file; a CLI flag/filter (e.g. only run worker matching X) that matches nothing; generating config from a template where the workers array was never filled.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Worker is missing a task
- launcherCommand must be a non-empty string
- orchestration template
- seedPaths entries must stay inside repoRoot
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/6f0cfc59a985fa89.
Report an issue: GitHub.
Appendix: 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 8321021c54)