{"record":{"id":"0fa025696356886e","repo":"github/spec-kit","slug":"preset-must-provide-at-least-one-template","errorCode":null,"errorMessage":"Preset must provide at least one template","messagePattern":"Preset must provide at least one template","errorType":"validation","errorClass":"PresetValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":387,"sourceCode":"        # later as ``AttributeError: 'str' object has no attribute 'filter'`` from\n        # inside .contains(). Neither is a PresetCompatibilityError, so both\n        # bypass the CLI's \"Compatibility Error\" handler and exit 1 with a raw\n        # traceback naming no field. An unquoted ``speckit_version: 1.0`` is an\n        # easy YAML slip. Mirrors the sibling IntegrationDescriptor, which already\n        # requires a non-empty string here.\n        if (\n            not isinstance(requires[\"speckit_version\"], str)\n            or not requires[\"speckit_version\"].strip()\n        ):\n            raise PresetValidationError(\n                \"Invalid requires.speckit_version: expected a non-empty string, \"\n                f\"got {type(requires['speckit_version']).__name__}\"\n            )\n\n        # Validate provides section\n        provides = self.data[\"provides\"]\n        if \"templates\" not in provides:\n            raise PresetValidationError(\n                \"Preset must provide at least one template\"\n            )\n\n        # Validate templates. Guard the container and each entry's shape so a\n        # malformed third-party preset.yml (e.g. ``templates: 5`` or\n        # ``templates: [null]``) raises a clean PresetValidationError the\n        # install handler already catches, instead of a raw TypeError\n        # ('int'/'NoneType' object is not iterable) that escapes to an\n        # unhandled traceback. Mirrors the sibling ExtensionManifest guards.\n        #\n        # Order matters: the container's TYPE is checked before its emptiness,\n        # so a FALSY non-list (``templates: 0``/``false``/``null``/``''``/``{}``)\n        # reports the accurate type error rather than the misleading \"must\n        # provide at least one template\". An empty list still reports the\n        # latter, since that genuinely is a list with no templates.\n        templates = provides[\"templates\"]\n        if not isinstance(templates, list):\n            raise PresetValidationError(","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L369-L405","documentation":"Error \"Preset must provide at least one template\" thrown in github/spec-kit.","triggerScenarios":"Thrown at src/specify_cli/presets/__init__.py:387 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Add at least one template entry under provides.templates in the preset manifest."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}