{"record":{"id":"7eda3fb200b0d229","repo":"Yeachan-Heo/oh-my-codex","slug":"skip-if-scrolling-must-be-boolean","errorCode":null,"errorMessage":"`skip_if_scrolling` must be boolean","messagePattern":"`skip_if_scrolling` must be boolean","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/tmux-hook.ts","lineNumber":159,"sourceCode":"  }\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,\n    skip_if_scrolling: parsed.skip_if_scrolling === false ? false : true,\n  };\n}\n\nasync function readValidatedConfig(cwd = process.cwd()): Promise<TmuxHookConfig> {\n  const configPath = tmuxHookConfigPath(cwd);","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/tmux-hook.ts#L141-L177","documentation":"The optional config field skip_if_scrolling, when present, must be strictly boolean. Unlike required fields, omission is allowed, but any non-boolean value (1/0, strings, null) fails.","triggerScenarios":"\"skip_if_scrolling\": \"yes\", 1, null, or any value that is not exactly true/false while the key exists.","commonSituations":"Users adding the optional flag with YAML-style yes/no; env-var templating producing strings; setting null to 'unset' it.","solutions":["Use an unquoted true/false, or delete the key entirely to use the default","Coerce templated values to real booleans before writing","Regenerate the config to see the canonical shape"],"exampleFix":"// before\n{\"skip_if_scrolling\": \"yes\"}\n// after\n{\"skip_if_scrolling\": true}","handlingStrategy":"type-guard","validationCode":"if ('skip_if_scrolling' in cfg && cfg.skip_if_scrolling !== true && cfg.skip_if_scrolling !== false) throw new Error('bad skip_if_scrolling');","typeGuard":"const isOptionalBool = (v: unknown): v is boolean | undefined => v === undefined || v === true || v === false;","tryCatchPattern":"try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('skip_if_scrolling')) { delete cfg.skip_if_scrolling; retry(); } }","preventionTips":["Omit the key rather than setting null/yes/no","Use real booleans for optional flags"],"tags":["config","validation","boolean","optional-field","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"}