Yeachan-Heo/oh-my-codex · error · Error

`log_level` must be one of: error, info, debug

Error message

`log_level` must be one of: error, info, debug

What it means

The config's log_level must be exactly one of the strings "error", "info", or "debug". Any other value (including uppercase variants, "warn", "warning", or missing) is rejected.

Solutions

  1. Use exactly "error", "info", or "debug"
  2. Pick "error" for quiet operation or "debug" for diagnostics
  3. Regenerate config with omx tmux-hook init

Example fix

// before
{"log_level": "warn"}
// after
{"log_level": "info"}
Defensive patterns

Strategy: validation

Validate before calling

const levels = new Set(['error','info','debug']);
if (!levels.has(cfg.log_level)) throw new Error('bad log_level');

Type guard

const isLogLevel = (v: unknown): v is 'error'|'info'|'debug' => v === 'error' || v === 'info' || v === 'debug';

Try / catch

try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('log_level')) fixLevel(); }

Prevention

When it happens

Trigger: "log_level": "warn", "INFO", "trace", a number, or the key omitted (undefined).

Common situations: Habitual use of warn/trace levels from other logging libraries; case mismatches; templated configs injecting unsupported levels.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/994996043920f988. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/tmux-hook.ts:156

  }
  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 },
    allowed_modes: allowedModes,
    cooldown_ms: cooldown,
    max_injections_per_session: maxInjections,
    prompt_template: promptTemplate,
    marker,
    dry_run: parsed.dry_run,
    log_level: parsed.log_level,
    skip_if_scrolling: parsed.skip_if_scrolling === false ? false : true,
  };
}

View on GitHub (pinned to 3ad79a8a6f)