github/spec-kit · error · ValidationError

Missing required field: {field}

Error message

Missing required field: {field}

What it means

First structural check in _validate(): each of the manifest's REQUIRED_FIELDS (schema_version, extension, and the other declared required top-level keys) must be present as a key. This checks presence only — shape and type are validated by subsequent checks. Note the companion comment: presence alone is not enough, empty/wrong-shape sections are caught by later guards.

Source

Thrown at src/specify_cli/extensions/__init__.py:267

            raise ValidationError(f"Manifest not found: {path}")
        except UnicodeDecodeError as e:
            raise ValidationError(
                f"Manifest is not valid UTF-8: {path} ({e.reason} at byte {e.start})"
            )
        except OSError as e:
            raise ValidationError(f"Could not read manifest {path}: {e}")
        if not isinstance(data, dict):
            raise ValidationError(
                f"Manifest must be a YAML mapping, got {type(data).__name__}: {path}"
            )
        return data

    def _validate(self):
        """Validate manifest structure and required fields."""
        # Check required top-level fields
        for field in self.REQUIRED_FIELDS:
            if field not in self.data:
                raise ValidationError(f"Missing required field: {field}")

        # Validate schema version
        if self.data["schema_version"] != self.SCHEMA_VERSION:
            raise ValidationError(
                f"Unsupported schema version: {self.data['schema_version']} "
                f"(expected {self.SCHEMA_VERSION})"
            )

        # The REQUIRED_FIELDS loop above only checks key PRESENCE, so a section
        # that is written but left empty (``provides:`` -> None) or given the
        # wrong shape (``provides: []``) passes it and then fails on first use:
        # ``field not in None`` raises TypeError and ``None.get(...)`` raises
        # AttributeError. Neither is a ValidationError, so both escape the
        # callers that already handle malformed manifests -- list_installed()'s
        # "Corrupted extension" fallback catches ValidationError only, so one bad
        # extension made ``specify extension list`` exit 1 with a raw
        # AttributeError instead of listing the rest. Guard each required
        # section's shape, mirroring the nested guards below ("Invalid

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Add the named key at the top level of the manifest.
  2. Compare against a known-good extension manifest or the bundled extension template.
  3. Re-run specify extension install to re-validate.

Example fix

# before
extension:
  id: my-ext

# after
schema_version: 2
extension:
  id: my-ext
Defensive patterns

Strategy: validation

Validate before calling

REQUIRED = {"schema_version", "extension"}  # mirror ExtensionManifest.REQUIRED_FIELDS
missing = REQUIRED - set(data)
if missing:
    raise SystemExit(f"manifest missing required fields: {sorted(missing)}")

Try / catch

except ValidationError as e:
    if str(e).startswith("Missing required field"):
        add_named_field_and_revalidate(path)

Prevention

When it happens

Trigger: Manifest mapping is missing a required top-level key, e.g. no `schema_version:` or no `extension:` block; validation raises naming the exact missing field.

Common situations: Draft manifests written from memory omitting a field; renaming a key (e.g. `metadata:` instead of `extension:`); fields commented out during debugging and forgotten; schema evolution between Specify versions changing the required set.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/056152025bb40c51. Report an issue: GitHub.