github/spec-kit · error · PresetValidationError

Failed to read catalog config {config_path}: {e}

Error message

Failed to read catalog config {config_path}: {e}

What it means

The preset catalog config file (YAML) could not be read or parsed. The loader catches yaml.YAMLError, OSError, and UnicodeError from yaml.safe_load()/read_text() and re-raises them as PresetValidationError so callers get one clean validation error instead of raw parser/IO tracebacks.

Source

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

        """Load catalog stack configuration from a YAML file.

        Args:
            config_path: Path to preset-catalogs.yml

        Returns:
            Ordered list of PresetCatalogEntry objects, or None if file
            doesn't exist or contains no valid catalog entries.

        Raises:
            PresetValidationError: If any catalog entry has an invalid URL,
                the file cannot be parsed, or a priority value is invalid.
        """
        if not config_path.exists():
            return None
        try:
            data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
        except (yaml.YAMLError, OSError, UnicodeError) as e:
            raise PresetValidationError(
                f"Failed to read catalog config {config_path}: {e}"
            )
        if not isinstance(data, dict):
            raise PresetValidationError(
                f"Invalid catalog config {config_path}: expected a mapping at root, got {type(data).__name__}"
            )
        catalogs_data = data.get("catalogs", [])
        if not catalogs_data:
            return None
        if not isinstance(catalogs_data, list):
            raise PresetValidationError(
                f"Invalid catalog config: 'catalogs' must be a list, got {type(catalogs_data).__name__}"
            )
        entries: List[PresetCatalogEntry] = []
        for idx, item in enumerate(catalogs_data):
            if not isinstance(item, dict):
                raise PresetValidationError(
                    f"Invalid catalog entry at index {idx}: expected a mapping, got {type(item).__name__}"

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Validate the YAML syntax with a linter or 'python -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" <file>' and fix the reported parse error
  2. Confirm the file is UTF-8 encoded (no BOM issues / locale-encoded bytes)
  3. Check file permissions on the catalog config path and make it readable
  4. If the file was corrupted (truncated write), delete it and let the tool regenerate defaults

Example fix

# before (broken YAML)
catalogs:
  - url: https://example.com/catalog.json
    priority: 1
  - url: https://other.com/catalog.json  # missing colon above / bad indent

# after
catalogs:
  - url: https://example.com/catalog.json
    priority: 1
  - url: https://other.com/catalog.json
    priority: 2
Defensive patterns

Strategy: validation

Validate before calling

import yaml, pathlib
p = pathlib.Path(catalog_config_path)
if p.exists():
    text = p.read_bytes().decode("utf-8")          # UnicodeError surfaces early
    data = yaml.safe_load(text)                     # YAMLError surfaces early
    assert isinstance(data, dict), "root must be a mapping"

Try / catch

try:
    catalogs = manager.load_catalog_config(path)
except PresetValidationError as e:
    # points at the exact file and parser/IO reason
    raise ConfigError(f"catalog config unusable: {e}") from e

Prevention

When it happens

Trigger: Calling load_catalog_config (or anything that reads ~/.specify/presets catalogs config, e.g. 'specify preset' commands) when the YAML file exists but has a syntax error, is unreadable due to file permissions, or contains bytes that are not valid UTF-8.

Common situations: Hand-editing the catalog YAML and leaving a stray tab, unclosed quote, or bad indentation; a truncated file from a crashed write; a non-UTF-8 encoded file created on Windows; a read-only home directory causing OSError.

Related errors


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