{"record":{"id":"d9a8be53f2ecbfcd","repo":"github/spec-kit","slug":"command-entry-name-must-be-a-non-empty-string","errorCode":null,"errorMessage":"Command entry 'name' must be a non-empty string","messagePattern":"Command entry 'name' must be a non-empty string","errorType":"validation","errorClass":"IntegrationDescriptorError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/integrations/catalog.py","lineNumber":796,"sourceCode":"                \"Invalid provides.scripts: expected a list\"\n            )\n        if not commands and not scripts:\n            raise IntegrationDescriptorError(\n                \"Integration must provide at least one command or script\"\n            )\n        for cmd in commands:\n            if not isinstance(cmd, dict):\n                raise IntegrationDescriptorError(\n                    \"Each command entry must be a mapping\"\n                )\n            if \"name\" not in cmd or \"file\" not in cmd:\n                raise IntegrationDescriptorError(\n                    \"Command entry missing 'name' or 'file'\"\n                )\n            cmd_name = cmd[\"name\"]\n            cmd_file = cmd[\"file\"]\n            if not isinstance(cmd_name, str) or not cmd_name.strip():\n                raise IntegrationDescriptorError(\n                    \"Command entry 'name' must be a non-empty string\"\n                )\n            if not isinstance(cmd_file, str) or not cmd_file.strip():\n                raise IntegrationDescriptorError(\n                    \"Command entry 'file' must be a non-empty string\"\n                )\n            if os.path.isabs(cmd_file) or \"..\" in Path(cmd_file).parts or Path(cmd_file).drive or Path(cmd_file).anchor:\n                raise IntegrationDescriptorError(\n                    f\"Command entry 'file' must be a relative path without '..': {cmd_file}\"\n                )\n        for script_entry in scripts:\n            if not isinstance(script_entry, str) or not script_entry.strip():\n                raise IntegrationDescriptorError(\n                    \"Script entry must be a non-empty string\"\n                )\n            if os.path.isabs(script_entry) or \"..\" in Path(script_entry).parts or Path(script_entry).drive or Path(script_entry).anchor:\n                raise IntegrationDescriptorError(\n                    f\"Script entry must be a relative path without '..': {script_entry}\"","sourceCodeStart":778,"sourceCodeEnd":814,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/integrations/catalog.py#L778-L814","documentation":"Raised by IntegrationDescriptor._validate() (src/specify_cli/integrations/catalog.py:796) when a provides.commands entry's 'name' value is not a string or is empty/whitespace-only. Command names become file stems and identifiers downstream, so they must be non-empty strings.","triggerScenarios":"A command entry with 'name: 123', 'name: null', 'name: \"\"', or 'name: \"   \"'; the isinstance/strip check fails and IntegrationDescriptorError is raised.","commonSituations":"YAML unquoted values parsed as non-strings (numbers, booleans, null); deleting a name's text while leaving the key; using a numeric command id.","solutions":["Quote the name and give it a non-empty value: name: \"plan\".","Ensure the value is a string, not a YAML number/boolean/null.","Re-validate the descriptor."],"exampleFix":"# before\n- name: 0123\n  file: commands/plan.md\n\n# after\n- name: \"plan\"\n  file: commands/plan.md","handlingStrategy":"type-guard","validationCode":"def bad_names(commands):\n    return [c for c in commands\n            if not isinstance(c.get(\"name\"), str) or not c[\"name\"].strip()]","typeGuard":"def is_nonempty_str(v) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":null,"preventionTips":["Quote command names in YAML so they parse as strings.","Avoid numeric or boolean-looking names.","Never leave 'name:' with an empty value."],"tags":["yaml","validation","integration-descriptor","spec-kit"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}