{"record":{"id":"30383caad1d46847","repo":"affaan-m/ECC","slug":"worker-workername-is-missing-a-launchercommand","errorCode":null,"errorMessage":"Worker ${workerName} is missing a launcherCommand","messagePattern":"Worker (.+?) is missing a launcherCommand","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/tmux-worktree-orchestrator.js","lineNumber":229,"sourceCode":"    const handoffFilePath = path.join(workerCoordinationDir, 'handoff.md');\n    const statusFilePath = path.join(workerCoordinationDir, 'status.md');\n    const launcherCommand = worker.launcherCommand || defaultLauncher;\n    const workerSeedPaths = normalizeSeedPaths(worker.seedPaths, repoRoot);\n    const seedPaths = normalizeSeedPaths([...globalSeedPaths, ...workerSeedPaths], repoRoot);\n    const templateVariables = buildTemplateVariables({\n      branch_name: branchName,\n      handoff_file: handoffFilePath,\n      repo_root: repoRoot,\n      session_name: sessionName,\n      status_file: statusFilePath,\n      task_file: taskFilePath,\n      worker_name: workerName,\n      worker_slug: workerSlug,\n      worktree_path: worktreePath\n    });\n\n    if (!launcherCommand) {\n      throw new Error(`Worker ${workerName} is missing a launcherCommand`);\n    }\n\n    const gitArgs = ['worktree', 'add', '-b', branchName, worktreePath, baseRef];\n\n    return {\n      branchName,\n      coordinationDir: workerCoordinationDir,\n      gitArgs,\n      gitCommand: formatCommand('git', gitArgs),\n      handoffFilePath,\n      launchCommand: renderTemplate(launcherCommand, templateVariables),\n      repoRoot,\n      sessionName,\n      seedPaths,\n      statusFilePath,\n      task: worker.task.trim(),\n      taskFilePath,\n      workerName,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/tmux-worktree-orchestrator.js#L211-L247","documentation":"Thrown inside the workers.map loop after templateVariables are built, when neither the worker's own launcherCommand nor the global default launcherCommand (config.launcherCommand) is a non-empty string. Up to this point the worker has a task and a unique slug, but there is no command to actually launch inside the tmux pane. Aborting here prevents producing a plan that cannot be executed.","triggerScenarios":"config.launcherCommand is unset and a worker omits launcherCommand; config.launcherCommand = '' and the worker has no override; only some workers specify launcherCommand and one of them does not; launcherCommand is whitespace-only and the || fallback chain treats it as empty.","commonSituations":"Mixed config where the global default was removed but per-worker overrides were not added on every entry; a CLI mode that requires explicit per-worker launcherCommand but the user only set some; refactoring splits a single launcher into per-worker launchers and misses one.","solutions":["Set a non-empty config.launcherCommand so all workers inherit it, OR set worker.launcherCommand on every worker.","Validate before calling: const ok = workers.every(w => (w.launcherCommand || config.launcherCommand || '').trim().length > 0);","Use the worker name in the message to find the offending entry.","Prefer the global default for a homogeneous fleet; only override per worker when they truly differ."],"exampleFix":"// before\nbuildOrchestrationPlan({\n  repoRoot,\n  workers: [\n    { name: 'alpha', task: '...', launcherCommand: 'claude \"{task_file}\"' },\n    { name: 'beta',  task: '...' },   // no launcher, no global default\n  ],\n});\n// -> Worker beta is missing a launcherCommand\n\n// after\nbuildOrchestrationPlan({\n  repoRoot,\n  launcherCommand: 'claude \"{task_file}\"',   // global default\n  workers: [\n    { name: 'alpha', task: '...' },\n    { name: 'beta',  task: '...' },\n  ],\n});","handlingStrategy":"validation","validationCode":"function ensureLauncherOnAll(config) {\n  const global = (config.launcherCommand || '').trim();\n  config.workers.forEach(w => {\n    if (!(w.launcherCommand || global).trim()) {\n      throw new Error(`Worker ${w.name || '?'} has no launcherCommand`);\n    }\n  });\n}\n\nensureLauncherOnAll(config);\nbuildOrchestrationPlan(config);","typeGuard":"function allWorkersHaveLauncher(config) {\n  const global = (config?.launcherCommand || '').trim();\n  return config.workers.every(w => Boolean((w.launcherCommand || global).trim()));\n}","tryCatchPattern":"try {\n  buildOrchestrationPlan(config);\n} catch (error) {\n  if (/is missing a launcherCommand/.test(error.message)) {\n    config.launcherCommand = DEFAULT_LAUNCHER;\n    buildOrchestrationPlan(config);\n    return;\n  }\n  throw error;\n}","preventionTips":["Set a global config.launcherCommand so workers inherit it by default.","Only override launcherCommand per worker when the launchers truly differ.","Validate the workers array against a schema that requires either a global or per-worker launcher.","Surface the worker name from the message to pinpoint the gap."],"tags":["orchestration","configuration","validation","launcher"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}