{"record":{"id":"8aeaf8e2aab76901","repo":"Yeachan-Heo/oh-my-codex","slug":"prompt-template-must-be-a-non-empty-string","errorCode":null,"errorMessage":"`prompt_template` must be a non-empty string","messagePattern":"`prompt_template` must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/tmux-hook.ts","lineNumber":146,"sourceCode":"\n  const allowedModes = parsed.allowed_modes;\n  if (!Array.isArray(allowedModes) || allowedModes.length === 0 || allowedModes.some(v => typeof v !== 'string')) {\n    throw new Error('`allowed_modes` must be a non-empty string array');\n  }\n\n  const cooldown = parsed.cooldown_ms;\n  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 },","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/tmux-hook.ts#L128-L164","documentation":"The config's prompt_template must be a non-empty, non-whitespace string; it is the text template injected into the tmux target. Empty, whitespace-only, non-string, or missing values fail.","triggerScenarios":"\"prompt_template\": \"\", \"  \", a number, or the key omitted (undefined).","commonSituations":"Templates moved to a separate file leaving an empty placeholder; templating engines stripping content; renaming the key.","solutions":["Provide a meaningful template string with the expected placeholders","Check docs for supported placeholder tokens (e.g. selection, pane id)","Regenerate via omx tmux-hook init"],"exampleFix":"// before\n{\"prompt_template\": \"\"}\n// after\n{\"prompt_template\": \"Context from tmux: {selection}\"}","handlingStrategy":"type-guard","validationCode":"if (typeof cfg.prompt_template !== 'string' || cfg.prompt_template.trim() === '') throw new Error('bad prompt_template');","typeGuard":"const isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.trim() !== '';","tryCatchPattern":"try { await loadConfig(); } catch (e) { if (e instanceof Error && e.message.includes('prompt_template')) fixTemplate(); }","preventionTips":["Fill template placeholders before saving config","Verify placeholder token names against the docs"],"tags":["config","validation","string","template","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"}