{"record":{"id":"17cdda16abb3f650","repo":"github/spec-kit","slug":"script-entry-must-be-a-non-empty-string","errorCode":null,"errorMessage":"Script entry must be a non-empty string","messagePattern":"Script entry must be a non-empty string","errorType":"validation","errorClass":"IntegrationDescriptorError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/integrations/catalog.py","lineNumber":809,"sourceCode":"                    \"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}\"\n                )\n\n    # -- Property accessors -----------------------------------------------\n\n    @property\n    def id(self) -> str:\n        return self.data[\"integration\"][\"id\"]\n\n    @property\n    def name(self) -> str:\n        return self.data[\"integration\"][\"name\"]\n\n    @property","sourceCodeStart":791,"sourceCodeEnd":827,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/integrations/catalog.py#L791-L827","documentation":"Raised by IntegrationDescriptor._validate() (src/specify_cli/integrations/catalog.py:809) when an element of provides.scripts is not a string or is empty/whitespace-only. Unlike command entries (mappings), script entries are plain relative-path strings, and each must be non-empty before the path-safety check runs.","triggerScenarios":"A descriptor with 'provides: scripts: [null, setup.sh, \"\"]' or a script entry parsed as a number/mapping; the isinstance/strip check in the for-loop over scripts raises.","commonSituations":"Mixing command-style mappings into the scripts list; YAML list entries that are empty lines or placeholder nulls; converting a map of script names to paths without unwrapping.","solutions":["Make every provides.scripts element a non-empty string path.","Remove null/empty placeholders from the list.","Move any command mappings (name/file) into provides.commands instead.","Re-validate the descriptor."],"exampleFix":"# before\nprovides:\n  scripts:\n    - {name: setup, file: setup.sh}\n\n# after\nprovides:\n  scripts:\n    - scripts/bash/setup.sh","handlingStrategy":"type-guard","validationCode":"def bad_script_entries(scripts):\n    return [s for s in scripts if not isinstance(s, str) or not s.strip()]","typeGuard":"def is_script_entry(v) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":null,"preventionTips":["Scripts are plain strings, not mappings — put name/file entries in commands.","Remove empty or null list items.","Validate the whole provides block with a helper before loading."],"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"}