Yeachan-Heo/oh-my-codex · error · Error
tmux-hook config must be a JSON object
Error message
tmux-hook config must be a JSON object
What it means
The tmux-hook config file was parsed as JSON but the result is not an object (null, array, number, string, or boolean). parseConfig requires a top-level JSON object before field-by-field validation proceeds.
Source
Thrown at src/cli/tmux-hook.ts:111
function omxDir(cwd = process.cwd()): string {
return omxRoot(cwd);
}
function tmuxHookConfigPath(cwd = process.cwd()): string {
return join(omxDir(cwd), 'tmux-hook.json');
}
function tmuxHookStatePath(cwd = process.cwd()): string {
return join(omxDir(cwd), 'state', 'tmux-hook-state.json');
}
function tmuxHookLogPath(cwd = process.cwd()): string {
return join(omxDir(cwd), 'logs', `tmux-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
}
function parseConfig(raw: unknown): TmuxHookConfig {
if (!raw || typeof raw !== 'object') {
throw new Error('tmux-hook config must be a JSON object');
}
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;View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Restore the config to a JSON object starting with { }
- Regenerate with omx tmux-hook init
- Validate the file with jq type check before running
Example fix
// before
// .omx/tmux-hook.json
null
// after
{"enabled":true,"target":{"type":"session","value":"main"},"allowed_modes":["vi"]} Defensive patterns
Strategy: type-guard
Validate before calling
const raw = JSON.parse(await readFile(cfg, 'utf-8'));
Type guard
function isTmuxHookConfigLike(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try { await runTmuxHook(); } catch (e) { if (e instanceof Error && e.message.includes('must be a JSON object')) fixAndRegenerateConfig(); else throw e; } Prevention
- Validate with jq before running: jq type .omx/tmux-hook.json should print object
- Regenerate config with omx tmux-hook init after manual edits
When it happens
Trigger: A config file containing e.g. `[]`, `null`, `"text"`, or `123` at `.omx/tmux-hook.json` (or wherever tmuxHookConfigPath points); also a JSON.parse result that yields a non-object.
Common situations: Hand-editing the config and replacing the object with a bare value; truncated or template-generated config files.
Related errors
- `enabled` must be boolean
- `target` is required
- `target.type` must be "session" or "pane"
- `target.value` must be a non-empty string
- `allowed_modes` must be a non-empty string array
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/2139a1b37a2cc650.
Report an issue: GitHub.