Yeachan-Heo/oh-my-codex · error · Error
`allowed_modes` must be a non-empty string array
Error message
`allowed_modes` must be a non-empty string array
What it means
The config's allowed_modes field must be an array containing at least one string; it controls which tmux modes (e.g. vi/copy mode) permit injection. Empty arrays, non-arrays, or arrays with non-string entries are rejected.
Source
Thrown at src/cli/tmux-hook.ts:131
const parsed = raw as Record<string, unknown>;
if (parsed.enabled !== true && parsed.enabled !== false) {
throw new Error('`enabled` must be boolean');
}
const target = parsed.target;
if (!target || typeof target !== 'object') {
throw new Error('`target` is required');
}
const targetObj = target as Record<string, unknown>;
if (targetObj.type !== 'session' && targetObj.type !== 'pane') {
throw new Error('`target.type` must be "session" or "pane"');
}
if (typeof targetObj.value !== 'string' || targetObj.value.trim() === '') {
throw new Error('`target.value` must be a non-empty string');
}
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');View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Set "allowed_modes": ["vi"] (array of strings, at least one)
- Check supported mode names in the docs/help
- Regenerate config via omx tmux-hook init
Example fix
// before
{"allowed_modes": "vi"}
// after
{"allowed_modes": ["vi"]} Defensive patterns
Strategy: type-guard
Validate before calling
const m = cfg.allowed_modes;
if (!Array.isArray(m) || m.length === 0 || m.some(x => typeof x !== 'string')) throw new Error('bad allowed_modes'); Type guard
const isStringArray = (v: unknown): v is string[] => Array.isArray(v) && v.length > 0 && v.every(x => typeof x === 'string');
Try / catch
try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('allowed_modes')) fixModes(); } Prevention
- Always use an array with at least one string, e.g. ["vi"]
- Avoid scalar shorthand for array fields
When it happens
Trigger: allowed_modes omitted (undefined), set to a single string "vi" instead of ["vi"], an empty array [], or [1, 2].
Common situations: Users writing a scalar where an array is expected; commenting out all modes; templating engines emitting empty lists.
Related errors
- tmux-hook config must be a JSON object
- `enabled` must be boolean
- `target` is required
- `target.type` must be "session" or "pane"
- `target.value` must be a non-empty string
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/87a29798ed518351.
Report an issue: GitHub.