affaan-m/ECC · error · Error
Unknown template variable
Error message
Unknown template variable: ${key} What it means
renderTemplate substitutes {key} placeholders in the launcher template and throws when the template references a variable key that is not present in the variables object. This stops half-rendered commands (with literal '{task}') from reaching the shell.
Solutions
- Add the missing key to the variables object passed to renderTemplate.
- Remove or correct the unknown placeholder in the template so it only uses supported keys.
- Check the renderTemplate replace regex/allowed keys and align template and variables.
- Log the variables object at call time to spot the mismatched key.
Example fix
// before
renderTemplate('run --task {task} --dir {dir}', { task: 'build' });
// after
renderTemplate('run --task {task} --dir {dir}', { task: 'build', dir: '/tmp/wt' }); Defensive patterns
Strategy: validation
Validate before calling
const required = [...template.matchAll(/\{([a-z_]+)\}/g)].map(m => m[1]);
const missing = required.filter(k => !(k in variables));
if (missing.length) throw new Error(`Missing template variables: ${missing.join(',')}`); Type guard
const hasAllVars = (t, v) => [...t.matchAll(/\{([a-z_]+)\}/g)].every(m => m[1] in v); Try / catch
try {
const cmd = renderTemplate(template, vars);
} catch (e) {
if (String(e.message).startsWith('Unknown template variable')) {
console.error('Template/variables mismatch:', e.message, Object.keys(vars));
}
throw e;
} Prevention
- Extract placeholders from the template and assert the variables superset before rendering.
- Keep template and variables construction adjacent in code.
- Avoid mixing camelCase and snake_case keys.
- Document the supported placeholder set next to the config.
When it happens
Trigger: Calling renderTemplate('claude --task {task} --root {root}', { task }) where 'root' is not in variables; renaming a placeholder in the template without updating the supplied variables map; a typo like {taskname} vs {taskName}.
Common situations: Editing the launcher command string in config to add a new placeholder without extending the variables passed by the orchestrator; case-sensitivity mistakes; copying a template from docs that uses variables this version doesn't support.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- launcherCommand must be a non-empty string
- buildOrchestrationPlan requires at least one worker
- failed ` : ''}
- Seed path does not exist in repoRoot
- seedPaths entries must stay inside repoRoot
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/a042825c44114fa5.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/tmux-worktree-orchestrator.js:23
const { spawnSync } = require('child_process');
function slugify(value, fallback = 'worker') {
const normalized = String(value || '')
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
return normalized || fallback;
}
function renderTemplate(template, variables) {
if (typeof template !== 'string' || template.trim().length === 0) {
throw new Error('launcherCommand must be a non-empty string');
}
return template.replace(/\{([a-z_]+)\}/g, (match, key) => {
if (!(key in variables)) {
throw new Error(`Unknown template variable: ${key}`);
}
return String(variables[key]);
});
}
function shellQuote(value) {
return `'${String(value).replace(/'/g, `'\\''`)}'`;
}
function formatCommand(program, args) {
return [program, ...args.map(shellQuote)].join(' ');
}
function buildTemplateVariables(values) {
return Object.entries(values).reduce((accumulator, [key, value]) => {
const stringValue = String(value);
const quotedValue = shellQuote(stringValue);
View on GitHub (pinned to 8321021c54)