{"record":{"id":"e1a4a46dfacabb02","repo":"Yeachan-Heo/oh-my-codex","slug":"marker-must-be-a-non-empty-string","errorCode":null,"errorMessage":"`marker` must be a non-empty string","messagePattern":"`marker` must be a non-empty string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/tmux-hook.ts","lineNumber":149,"sourceCode":"    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 },\n    allowed_modes: allowedModes,\n    cooldown_ms: cooldown,\n    max_injections_per_session: maxInjections,","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/tmux-hook.ts#L131-L167","documentation":"The config's marker must be a non-empty string; it is the sentinel marker the hook uses to tag/detect injected content. Empty, whitespace-only, non-string, or missing values fail.","triggerScenarios":"\"marker\": \"\", \"   \", numeric values, or the key omitted entirely.","commonSituations":"Assuming a default marker exists; wiping the field during edits; marker keys renamed between versions.","solutions":["Set a distinctive non-empty marker string, e.g. \"__OMX_INJECT__\"","Avoid markers that collide with normal shell output","Regenerate config with omx tmux-hook init for the default value"],"exampleFix":"// before\n{\"marker\": \"\"}\n// after\n{\"marker\": \"__OMX_HOOK__\"}","handlingStrategy":"type-guard","validationCode":"if (typeof cfg.marker !== 'string' || cfg.marker.trim() === '') throw new Error('bad marker');","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('`marker`')) fixMarker(); }","preventionTips":["Choose a unique sentinel like __OMX_HOOK__","Keep the marker from init output as the default"],"tags":["config","validation","string","marker","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"}