github/spec-kit · error · ValidationError

Could not read manifest {path}: {e}

Error message

Could not read manifest {path}: {e}

What it means

Catch-all for OS-level read failures of the extension manifest other than missing-file and decode errors: the open/read raised OSError (e.g. permission denied, I/O error). The underlying errno message is embedded in the ValidationError.

Source

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

        self.warnings: List[str] = []
        self.data = self._load_yaml(manifest_path)
        self._validate()

    def _load_yaml(self, path: Path) -> dict:
        """Load YAML file safely."""
        try:
            with open(path, "r", encoding="utf-8") as f:
                data = yaml.safe_load(f)
        except yaml.YAMLError as e:
            raise ValidationError(f"Invalid YAML in {path}: {e}")
        except FileNotFoundError:
            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})"

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Read the embedded errno text — 'Permission denied' means fix modes/ownership (`chmod 644`, `chown`); 'Is a directory' means the path is wrong.
  2. Ensure the user running specify has read access to every component of the path.
  3. In containers, check volume mount permissions and uid mapping.

Example fix

# before
$ ls -l .specify/extensions/my-ext/extension.yaml
-rw------- 1 root root ... extension.yaml

# after
$ chmod 644 .specify/extensions/my-ext/extension.yaml
Defensive patterns

Strategy: try-catch

Validate before calling

import os
if not os.access(manifest_path, os.R_OK):
    raise SystemExit(f"no read permission for {manifest_path}")

Try / catch

except ValidationError as e:
    if "Could not read manifest" in str(e):
        diagnose_errno(e)  # Permission denied -> chmod/chown; Is a directory -> wrong path

Prevention

When it happens

Trigger: The manifest exists and decodes but the process cannot read it — EACCES on restrictive file modes, a directory instead of a file (IsADirectoryError is an OSError), or a failing disk/NFS mount.

Common situations: Manifest chmod 600 owned by another user; files extracted from an archive that lost permissions; running the CLI as a different user or inside a container with mismatched uid; the manifest path is actually a directory.

Related errors


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