{"record":{"id":"a37ab62a98b4b64c","repo":"yamadashy/repomix","slug":"skill-name-cannot-be-empty-after-normalization","errorCode":null,"errorMessage":"Skill name cannot be empty after normalization","messagePattern":"Skill name cannot be empty after normalization","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/skill/skillUtils.ts","lineNumber":40,"sourceCode":" * Validates and normalizes a skill name.\n * Converts to kebab-case and truncates to 64 characters.\n * Also rejects path traversal attempts.\n */\nexport const validateSkillName = (name: string): string => {\n  // Reject path separators and null bytes to prevent path traversal\n  if (name.includes('/') || name.includes('\\\\') || name.includes('\\0')) {\n    throw new Error('Skill name cannot contain path separators or null bytes');\n  }\n\n  // Reject dot-only names (., .., ...)\n  if (/^\\.+$/.test(name)) {\n    throw new Error('Skill name cannot consist only of dots');\n  }\n\n  const kebabName = toKebabCase(name);\n\n  if (kebabName.length === 0) {\n    throw new Error('Skill name cannot be empty after normalization');\n  }\n\n  return kebabName.substring(0, SKILL_NAME_MAX_LENGTH);\n};\n\n/**\n * Converts a string to Title Case.\n * Handles kebab-case, snake_case, and other separators.\n */\nconst toTitleCase = (str: string): string => {\n  return str\n    .replace(/[-_]/g, ' ')\n    .replace(/\\b\\w/g, (char) => char.toUpperCase())\n    .trim();\n};\n\n/**\n * Generates a human-readable project name from root directories.","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/yamadashy/repomix/blob/f465ad909315a22120636baf03fa5e28701a50cb/src/core/skill/skillUtils.ts#L22-L58","documentation":"After converting to kebab-case, validateSkillName checks that the result is non-empty and throws if normalization erased every character (e.g. input made entirely of characters stripped by toKebabCase like '///' or '--'). It guarantees the generated skill directory name is usable.","triggerScenarios":"Passing a name whose kebab-case transformation yields an empty string — e.g. only symbols/punctuation, whitespace-only, or characters removed by the normalization pipeline.","commonSituations":"Auto-deriving names from URLs or titles that are pure punctuation/emoji; locale-specific input where all characters are stripped; an upstream sanitizer that already removed alphanumerics.","solutions":["Check for alphanumeric content before calling and supply a meaningful fallback name.","Improve the input source (e.g. use the repository name rather than a symbolic URL fragment).","Fall back to a default like 'repomix-skill' when the derived name would be empty."],"exampleFix":"// before\nconst name = validateSkillName(title); // title = '### !!!'\n// after\nconst fallback = title && toKebabCase(title).length > 0 ? title : 'repomix-skill';\nconst name = validateSkillName(fallback);","handlingStrategy":"fallback","validationCode":"const derived = toKebabCase(raw);\nconst name = validateSkillName(derived.length > 0 ? raw : 'repomix-skill');","typeGuard":"const hasNameableContent = (s: string): boolean => /[a-z0-9]/i.test(s);","tryCatchPattern":"try {\n  const name = validateSkillName(input);\n} catch (e) {\n  if (e.message.includes('empty after normalization')) {\n    const name = validateSkillName('repomix-skill');\n  } else throw e;\n}","preventionTips":["Verify the input contains alphanumeric characters before normalizing.","Derive names from reliable fields (repo name) rather than decorative text.","Always pair name generation with a non-empty fallback.","Test name generation with punctuation-only and emoji inputs."],"tags":["validation","normalization","skill"],"backgroundTag":"empty-identifier","analyzedSha":"f465ad909315a22120636baf03fa5e28701a50cb","analyzedAt":"2026-08-29T01:27:42.024Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}