{"record":{"id":"c4a588a6d2641c00","repo":"github/spec-kit","slug":"missing-extension-field","errorCode":null,"errorMessage":"Missing extension.{field}","messagePattern":"Missing extension\\.(.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/extensions/__init__.py","lineNumber":308,"sourceCode":"        ext = self.data[\"extension\"]\n        if not isinstance(ext, dict):\n            raise ValidationError(\n                f\"Invalid extension: expected a mapping, got {type(ext).__name__}\"\n            )\n        # Check presence AND type: the format/version checks below feed these\n        # values straight to ``re.match`` and ``packaging.Version``, both of\n        # which raise a bare TypeError on a non-string. YAML makes that an easy\n        # authoring slip -- unquoted ``version: 1.0`` parses as a float and\n        # ``id: 2`` as an int -- and TypeError is not a ValidationError, so it\n        # escapes every caller that already handles a malformed manifest (see\n        # list_installed()'s \"Corrupted extension\" fallback, which catches\n        # ValidationError only, making one bad extension exit ``specify\n        # extension list`` with a raw traceback and hide the healthy ones).\n        # Mirrors the sibling IntegrationDescriptor, which already type-checks\n        # the same four fields.\n        for field in [\"id\", \"name\", \"version\", \"description\"]:\n            if field not in ext:\n                raise ValidationError(f\"Missing extension.{field}\")\n            if not isinstance(ext[field], str):\n                raise ValidationError(\n                    f\"Invalid extension.{field}: expected a string, \"\n                    f\"got {type(ext[field]).__name__}\"\n                )\n\n        # Validate extension ID format\n        if not re.match(r\"^[a-z0-9-]+$\", ext[\"id\"]):\n            raise ValidationError(\n                f\"Invalid extension ID '{ext['id']}': \"\n                \"must be lowercase alphanumeric with hyphens only\"\n            )\n\n        # Validate semantic version\n        try:\n            pkg_version.Version(ext[\"version\"])\n        except pkg_version.InvalidVersion:\n            raise ValidationError(f\"Invalid version: {ext['version']}\")","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/extensions/__init__.py#L290-L326","documentation":"Raised when the `extension` mapping is missing one of the four metadata fields: id, name, version, or description. Presence is checked per-field before the type check, and the message names the exact missing key (e.g. 'Missing extension.version').","triggerScenarios":"Manifest's extension block defines id/name/description but omits `version:` (the most commonly forgotten), or any other of the four; the field loop raises on the first absent key.","commonSituations":"Hand-authored manifests; copying a partial example; deleting a field while editing and forgetting to restore it; assuming description is optional (it is not).","solutions":["Add the named field under `extension:`.","Ensure all four — id, name, version, description — are present.","Quote version as a string (`version: \"1.0.0\"`) to avoid the float-type trap caught by the next check."],"exampleFix":"# before\nextension:\n  id: my-ext\n  name: My Extension\n  description: Does things\n\n# after\nextension:\n  id: my-ext\n  name: My Extension\n  version: \"1.0.0\"\n  description: Does things","handlingStrategy":"validation","validationCode":"EXT_FIELDS = [\"id\", \"name\", \"version\", \"description\"]\nmissing = [f for f in EXT_FIELDS if f not in data.get(\"extension\", {})]\nif missing:\n    raise SystemExit(f\"extension section missing: {missing}\")","typeGuard":null,"tryCatchPattern":"except ValidationError as e:\n    if str(e).startswith(\"Missing extension.\"):\n        add_missing_metadata_field(path)","preventionTips":["All four metadata fields are mandatory — including description.","Use a template or schema-checked editor plugin for extension.yaml."],"tags":["manifest","validation","extensions","required-fields"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}