Yeachan-Heo/oh-my-codex · error · Error
`prompt_template` must be a non-empty string
Error message
`prompt_template` must be a non-empty string
What it means
The config's prompt_template must be a non-empty, non-whitespace string; it is the text template injected into the tmux target. Empty, whitespace-only, non-string, or missing values fail.
Source
Thrown at src/cli/tmux-hook.ts:146
const allowedModes = parsed.allowed_modes;
if (!Array.isArray(allowedModes) || allowedModes.length === 0 || allowedModes.some(v => typeof v !== 'string')) {
throw new Error('`allowed_modes` must be a non-empty string array');
}
const cooldown = parsed.cooldown_ms;
const maxInjections = parsed.max_injections_per_session;
if (typeof cooldown !== 'number' || cooldown < 0 || !Number.isFinite(cooldown)) {
throw new Error('`cooldown_ms` must be a non-negative number');
}
if (typeof maxInjections !== 'number' || maxInjections < 1 || !Number.isFinite(maxInjections)) {
throw new Error('`max_injections_per_session` must be >= 1');
}
const promptTemplate = parsed.prompt_template;
const marker = parsed.marker;
if (typeof promptTemplate !== 'string' || promptTemplate.trim() === '') {
throw new Error('`prompt_template` must be a non-empty string');
}
if (typeof marker !== 'string' || marker.trim() === '') {
throw new Error('`marker` must be a non-empty string');
}
if (parsed.dry_run !== true && parsed.dry_run !== false) {
throw new Error('`dry_run` must be boolean');
}
if (parsed.log_level !== 'error' && parsed.log_level !== 'info' && parsed.log_level !== 'debug') {
throw new Error('`log_level` must be one of: error, info, debug');
}
if (parsed.skip_if_scrolling !== undefined && parsed.skip_if_scrolling !== true && parsed.skip_if_scrolling !== false) {
throw new Error('`skip_if_scrolling` must be boolean');
}
return {
enabled: parsed.enabled,
target: { type: targetObj.type, value: targetObj.value },View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Provide a meaningful template string with the expected placeholders
- Check docs for supported placeholder tokens (e.g. selection, pane id)
- Regenerate via omx tmux-hook init
Example fix
// before
{"prompt_template": ""}
// after
{"prompt_template": "Context from tmux: {selection}"} Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof cfg.prompt_template !== 'string' || cfg.prompt_template.trim() === '') throw new Error('bad prompt_template'); Type guard
const isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.trim() !== '';
Try / catch
try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('prompt_template')) fixTemplate(); } Prevention
- Fill template placeholders before saving config
- Verify placeholder token names against the docs
When it happens
Trigger: "prompt_template": "", " ", a number, or the key omitted (undefined).
Common situations: Templates moved to a separate file leaving an empty placeholder; templating engines stripping content; renaming the key.
Related errors
- `target.value` must be a non-empty string
- `marker` must be a non-empty string
- tmux-hook config must be a JSON object
- `enabled` must be boolean
- `target` is required
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/8aeaf8e2aab76901.
Report an issue: GitHub.