{"record":{"id":"6126a899b7c9cb03","repo":"Yeachan-Heo/oh-my-codex","slug":"mode-must-match-a-za-z0-9-1-64","errorCode":null,"errorMessage":"mode must match ^[A-Za-z0-9_-]{1,64}$","messagePattern":"mode must match \\^\\[A-Za-z0-9_-\\](.+?)\\$","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mcp/state-paths.ts","lineNumber":145,"sourceCode":"}\n\n\nexport function validateStateModeSegment(mode: unknown): string {\n  if (typeof mode !== 'string') {\n    throw new Error('mode must be a string');\n  }\n  const normalized = mode.trim();\n  if (!normalized) {\n    throw new Error('mode must be a non-empty string');\n  }\n  if (normalized.includes('..')) {\n    throw new Error('mode must not contain \"..\"');\n  }\n  if (normalized.includes('/') || normalized.includes('\\\\')) {\n    throw new Error('mode must not contain path separators');\n  }\n  if (!STATE_MODE_SEGMENT_PATTERN.test(normalized)) {\n    throw new Error('mode must match ^[A-Za-z0-9_-]{1,64}$');\n  }\n  return normalized;\n}\n\nexport function getStateFilename(mode: string): string {\n  return `${validateStateModeSegment(mode)}${STATE_FILE_SUFFIX}`;\n}\n\nexport function validateStateFileName(fileName: unknown): string {\n  if (typeof fileName !== 'string') {\n    throw new Error('fileName must be a string');\n  }\n  const normalized = fileName.trim();\n  if (!normalized) {\n    throw new Error('fileName must be a non-empty string');\n  }\n  if (normalized.includes('..')) {\n    throw new Error('fileName must not contain \"..\"');","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/mcp/state-paths.ts#L127-L163","documentation":"Final pattern check in validateStateModeSegment: after passing the type, emptiness, '..' and separator checks, mode must match ^[A-Za-z0-9_-]{1,64}$ (dots are NOT allowed here, unlike filenames).","triggerScenarios":"mode: \"night.mode\" (dot rejected), mode longer than 64 chars, or mode with spaces/unicode.","commonSituations":"Reusing a filename-style slug that contains dots; long generated mode names; assuming filename rules apply to mode segments.","solutions":["Use only letters, digits, underscore, hyphen; <=64 chars","Replace dots with hyphens: mode.replace(/\\./g, \"-\")","Shorten/hash overly long mode names"],"exampleFix":"// before\ngetStateFilename(\"v1.2.beta\");\n// after\ngetStateFilename(\"v1-2-beta\");","handlingStrategy":"validation","validationCode":"const MODE = /^[A-Za-z0-9_-]{1,64}$/;\nif (!MODE.test(mode)) mode = mode.replace(/[^A-Za-z0-9_-]/g, '-').slice(0, 64);","typeGuard":"function isValidModeSegment(v: string): boolean { return /^[A-Za-z0-9_-]{1,64}$/.test(v); }","tryCatchPattern":null,"preventionTips":["Remember mode forbids dots (stricter than fileName)","Slugify mode names from external sources"],"tags":["pattern-validation","state","mcp"],"backgroundTag":"id-format-invalid","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}