{"record":{"id":"6987e450e24f5170","repo":"affaan-m/ECC","slug":"launchercommand-must-be-a-non-empty-string","errorCode":null,"errorMessage":"launcherCommand must be a non-empty string","messagePattern":"launcherCommand must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/tmux-worktree-orchestrator.js","lineNumber":18,"sourceCode":"'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\nconst { spawnSync } = require('child_process');\n\nfunction slugify(value, fallback = 'worker') {\n  const normalized = String(value || '')\n    .trim()\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '');\n  return normalized || fallback;\n}\n\nfunction renderTemplate(template, variables) {\n  if (typeof template !== 'string' || template.trim().length === 0) {\n    throw new Error('launcherCommand must be a non-empty string');\n  }\n\n  return template.replace(/\\{([a-z_]+)\\}/g, (match, key) => {\n    if (!(key in variables)) {\n      throw new Error(`Unknown template variable: ${key}`);\n    }\n    return String(variables[key]);\n  });\n}\n\nfunction shellQuote(value) {\n  return `'${String(value).replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction formatCommand(program, args) {\n  return [program, ...args.map(shellQuote)].join(' ');\n}\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/tmux-worktree-orchestrator.js#L1-L36","documentation":"renderTemplate validates that the launcherCommand template is a non-empty string before substituting {variable} placeholders. It throws when the template is undefined, empty, or whitespace-only. This is the entry-point guard for generating worker launcher commands in the tmux orchestrator.","triggerScenarios":"Calling renderTemplate(undefined, vars) or renderTemplate('   ', vars); passing config.launcherCommand when that config key was never set; spreading a config object where launcherCommand is absent.","commonSituations":"Omitting launcherCommand from the orchestration config; a config loader that returns an empty string on parse failure; renaming the config key so the template no longer reaches renderTemplate.","solutions":["Provide a non-empty launcherCommand template in the config, e.g. 'claude --task {task} --worktree {worktreePath}'.","Check the config loading path for silently producing '' or undefined and add a load-time check.","Fall back to a known-good default template when the config value is empty.","Validate config with a schema (e.g. zod) requiring launcherCommand: z.string().min(1)."],"exampleFix":"// before\nrenderTemplate(config.launcherCommand, vars); // config.launcherCommand === ''\n// after\nconst template = config.launcherCommand || 'claude --task {task}';\nrenderTemplate(template, vars);","handlingStrategy":"validation","validationCode":"if (typeof launcherCommand !== 'string' || launcherCommand.trim().length === 0) throw new Error('launcherCommand is required in config');","typeGuard":"const hasTemplate = (c) => typeof c?.launcherCommand === 'string' && c.launcherCommand.trim().length > 0;","tryCatchPattern":"try {\n  renderTemplate(template, vars);\n} catch (e) {\n  if (String(e.message) === 'launcherCommand must be a non-empty string') {\n    console.error('launcherCommand missing/empty in orchestration config');\n  }\n  throw e;\n}","preventionTips":["Require launcherCommand in the config schema with min length 1.","Provide a default template constant for setups that omit it.","Fail fast at config load, not at render time.","Snapshot-test config parsing to catch empty-string regressions."],"tags":["template","validation","tmux"],"backgroundTag":"empty-required-field","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}