github/spec-kit · error · PresetValidationError

Invalid YAML in {path}: {e}

Error message

Invalid YAML in {path}: {e}

What it means

PresetValidationError raised by PresetManifest._load_yaml when yaml.safe_load fails with a YAMLError — the preset manifest file (YAML) has syntax errors such as bad indentation, unclosed quotes, or tabs. The full parser error (line/column) is embedded in the message.

Source

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

        """Load and validate preset manifest.

        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."""

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Read the embedded yaml error location (line:col) and fix the indentation/syntax there
  2. Validate locally: python -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" <file>
  3. Quote scalar strings that contain ': ' or start with special characters; use spaces, never tabs
  4. If the preset came from a repo, re-download the original file

Example fix

# before
name: my preset
commands:
	build: x   # tab + wrong nesting
# after
name: my preset
commands:
  build: x
Defensive patterns

Strategy: validation

Validate before calling

import yaml
try:
    with open(path, encoding="utf-8") as f:
        yaml.safe_load(f)
except yaml.YAMLError:
    fix_yaml_syntax(path)  # use the parser's line/col in the exception
except FileNotFoundError:
    resolve_correct_path()

Type guard

def is_valid_preset_yaml(path: Path) -> bool:
    try:
        with open(path, encoding="utf-8") as f:
            return isinstance(yaml.safe_load(f), (dict, type(None)))
    except (yaml.YAMLError, OSError):
        return False

Try / catch

from specify_cli.presets import PresetValidationError
try:
    manifest = PresetManifest(path)
except PresetValidationError as exc:
    if "Invalid YAML" in str(exc):
        report_yaml_error_and_exit(path, str(exc))
    raise

Prevention

When it happens

Trigger: Loading a preset manifest (specify init --preset / preset tooling) whose YAML is malformed: tab indentation, unquoted strings with ':', duplicate keys under strict parsing, or a truncated file.

Common situations: Hand-authoring preset manifests; copy-pasting YAML that lost indentation (e.g. from chat/HTML); merging conflicts that left markers; YAML 1.1 quirks like unquoted on/off/no booleans.

Related errors


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