{"record":{"id":"78b4ae7ae81e91de","repo":"zylon-ai/private-gpt","slug":"name-invalid-format","errorCode":"NAME_INVALID_FORMAT","errorMessage":"name must be lowercase alphanumeric with single hyphens only","messagePattern":"name must be lowercase alphanumeric with single hyphens only","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/skills/parser.py","lineNumber":40,"sourceCode":"    )\n    license: str | None = Field(default=None)\n    compatibility: str | None = Field(default=None)\n    metadata: dict[str, str] | None = Field(default=None)\n    allowed_tools_raw: str | None = Field(default=None, alias=\"allowed-tools\")\n\n    @property\n    def allowed_tools(self) -> list[str] | None:\n        raw = self.allowed_tools_raw\n        if raw is None:\n            return None\n        tools = [token.strip() for token in raw.split(\" \") if token.strip()]\n        return tools or None\n\n    @field_validator(\"name\")\n    @classmethod\n    def validate_name(cls, value: str) -> str:\n        if not _NAME_RE.fullmatch(value):\n            raise ValueError(\n                \"name must be lowercase alphanumeric with single hyphens only\"\n            )\n        if \"--\" in value:\n            raise ValueError(\"name cannot contain consecutive hyphens\")\n        return value\n\n    @field_validator(\"metadata\", mode=\"before\")\n    @classmethod\n    def validate_metadata(\n        cls, value: dict[str, object] | None\n    ) -> dict[str, str] | None:\n        if value is None:\n            return value\n        return {\n            key: str(val) if not isinstance(val, str) else val\n            for key, val in value.items()\n            if key\n        }","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/skills/parser.py#L22-L58","documentation":"SkillFrontmatter's name field validator enforces the skill naming convention (lowercase alphanumeric plus single hyphens) via a full regex match and raises ValueError with code NAME_INVALID_FORMAT when the name does not conform. A second check rejects consecutive hyphens. This mirrors the Claude/agent skill packaging convention so skill names are filesystem- and URL-safe.","triggerScenarios":"Parsing a SKILL.md whose YAML frontmatter has a `name:` value like 'My Skill', 'data_loader', 'Data-Loader', 'a--b', or with leading/trailing hyphens — anything failing _NAME_RE.fullmatch.","commonSituations":"Hand-authored skills with human-readable names or underscores; names auto-generated from filenames containing spaces or uppercase; porting skills from systems with looser naming; copy-paste introducing invisible whitespace.","solutions":["Rename to lowercase-alphanumeric-with-single-hyphens: 'data-loader' instead of 'Data_Loader'.","Check for consecutive hyphens, leading/trailing hyphens, and stray whitespace in the name value.","If generating names from filenames, normalize: `re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')` and collapse repeats.","Validate names at authoring time with the same regex: ^[a-z0-9]+(-[a-z0-9]+)*$ style pattern."],"exampleFix":"# before (SKILL.md frontmatter)\n---\nname: Data_Loader\ndescription: loads data\n---\n\n# after\n---\nname: data-loader\ndescription: loads data\n---","handlingStrategy":"validation","validationCode":"import re\n\n_NAME_RE = re.compile(r\"^[a-z0-9]+(-[a-z0-9]+)*$\")\n\ndef valid_skill_name(name: str) -> bool:\n    return bool(_NAME_RE.fullmatch(name)) and \"--\" not in name\n\ndef slugify(name: str) -> str:\n    s = re.sub(r\"[^a-z0-9]+\", \"-\", name.lower()).strip(\"-\")\n    return s or \"unnamed-skill\"","typeGuard":"def is_valid_skill_name(value: str) -> bool:\n    return (\n        isinstance(value, str)\n        and bool(_NAME_RE.fullmatch(value))\n        and \"--\" not in value\n    )","tryCatchPattern":"try:\n    doc = parse_skill_markdown(content)\nexcept SkillValidationErrors as e:\n    if any(err.code is SkillErrorCode.NAME_INVALID_FORMAT for err in e.errors):\n        fix_name_and_revalidate()  # prompt author with slug suggestion\n    raise","preventionTips":["Slugify skill names automatically when generating from filenames or titles.","Lint SKILL.md frontmatter in CI with the same regex.","Never reuse human display titles as the name field."],"tags":["skills","validation","naming","frontmatter","yaml"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}