github/spec-kit · error · PresetValidationError

Manifest not found: {path}

Error message

Manifest not found: {path}

What it means

PresetValidationError raised when opening the preset manifest file raises FileNotFoundError — the YAML path passed to PresetManifest does not exist on disk. It is converted to a validation error so callers get one exception type for all bad-manifest conditions.

Source

Thrown at src/specify_cli/presets/__init__.py:290

        Args:
            manifest_path: Path to preset.yml file

        Raises:
            PresetValidationError: If manifest is invalid
        """
        self.path = manifest_path
        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 PresetValidationError(f"Invalid YAML in {path}: {e}")
        except FileNotFoundError:
            raise PresetValidationError(f"Manifest not found: {path}")
        except UnicodeDecodeError as e:
            raise PresetValidationError(
                f"Manifest is not valid UTF-8: {path} ({e.reason} at byte {e.start})"
            )
        except OSError as e:
            raise PresetValidationError(f"Could not read manifest {path}: {e}")
        if data is None:
            return {}
        if not isinstance(data, dict):
            raise PresetValidationError(
                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:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Verify the path exists: ls the exact path from the error message
  2. Use an absolute path or resolve it against a known base dir before passing it in
  3. If using a built-in/remote preset name, make sure it is downloaded to the expected location first

Example fix

# before
manifest = PresetManifest(Path("preset.yaml"))  # cwd is elsewhere
# after
base = Path(__file__).parent
manifest = PresetManifest(base / "presets" / "preset.yaml")
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
path = Path(preset_path)
if not path.is_file():
    raise SystemExit(f"preset manifest not found: {path}")
manifest = PresetManifest(path)

Type guard

def preset_manifest_exists(path: str | Path) -> bool:
    p = Path(path)
    return p.is_file() and p.suffix in {".yaml", ".yml"}

Try / catch

from specify_cli.presets import PresetValidationError
try:
    manifest = PresetManifest(path)
except PresetValidationError as exc:
    if "Manifest not found" in str(exc):
        locate_preset_or_prompt_user(path)
    raise

Prevention

When it happens

Trigger: Constructing PresetManifest(Path('presets/mine.yaml')) (or the preset CLI with --preset pointing at a missing file) — typo in the name, wrong working directory, or the preset not cloned/installed yet.

Common situations: Running from a different cwd so a relative preset path misses; referencing a preset from a repo not yet fetched; case-sensitivity mismatches between macOS and Linux; a missing file after a clean clone.

Related errors


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