{"record":{"id":"064619956eec37e7","repo":"Yeachan-Heo/oh-my-codex","slug":"dry-run-must-be-boolean","errorCode":null,"errorMessage":"`dry_run` must be boolean","messagePattern":"`dry_run` must be boolean","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/tmux-hook.ts","lineNumber":153,"sourceCode":"  const maxInjections = parsed.max_injections_per_session;\n  if (typeof cooldown !== 'number' || cooldown < 0 || !Number.isFinite(cooldown)) {\n    throw new Error('`cooldown_ms` must be a non-negative number');\n  }\n  if (typeof maxInjections !== 'number' || maxInjections < 1 || !Number.isFinite(maxInjections)) {\n    throw new Error('`max_injections_per_session` must be >= 1');\n  }\n\n  const promptTemplate = parsed.prompt_template;\n  const marker = parsed.marker;\n  if (typeof promptTemplate !== 'string' || promptTemplate.trim() === '') {\n    throw new Error('`prompt_template` must be a non-empty string');\n  }\n  if (typeof marker !== 'string' || marker.trim() === '') {\n    throw new Error('`marker` must be a non-empty string');\n  }\n\n  if (parsed.dry_run !== true && parsed.dry_run !== false) {\n    throw new Error('`dry_run` must be boolean');\n  }\n  if (parsed.log_level !== 'error' && parsed.log_level !== 'info' && parsed.log_level !== 'debug') {\n    throw new Error('`log_level` must be one of: error, info, debug');\n  }\n  if (parsed.skip_if_scrolling !== undefined && parsed.skip_if_scrolling !== true && parsed.skip_if_scrolling !== false) {\n    throw new Error('`skip_if_scrolling` must be boolean');\n  }\n\n  return {\n    enabled: parsed.enabled,\n    target: { type: targetObj.type, value: targetObj.value },\n    allowed_modes: allowedModes,\n    cooldown_ms: cooldown,\n    max_injections_per_session: maxInjections,\n    prompt_template: promptTemplate,\n    marker,\n    dry_run: parsed.dry_run,\n    log_level: parsed.log_level,","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/tmux-hook.ts#L135-L171","documentation":"The config's dry_run field must be strictly boolean (true/false). 1/0, \"true\"/\"false\" strings, or a missing key (undefined) are rejected.","triggerScenarios":"\"dry_run\": 1, \"dry_run\": \"true\", or omitting the key (it is required, not optional).","commonSituations":"Users assuming dry_run defaults to false when omitted; env-templated configs producing strings.","solutions":["Set \"dry_run\": true or false explicitly (unquoted boolean)","If templating, coerce with === 'true' style logic before serializing","Use omx tmux-hook init to regenerate defaults"],"exampleFix":"// before\n{\"dry_run\": \"true\"}\n// after\n{\"dry_run\": true}","handlingStrategy":"type-guard","validationCode":"if (cfg.dry_run !== true && cfg.dry_run !== false) throw new Error('dry_run must be boolean');","typeGuard":"const isBool = (v: unknown): v is boolean => v === true || v === false;","tryCatchPattern":"try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('dry_run')) fixDryRun(); }","preventionTips":["dry_run is required, not optional — always set it explicitly","Use unquoted booleans in JSON"],"tags":["config","validation","boolean","tmux-hook"],"backgroundTag":"config-schema-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}