github/spec-kit · error · ValidationError

Manifest is not valid UTF-8

Error message

Manifest is not valid UTF-8: {path} ({e.reason} at byte {e.start})

What it means

Raised when the extension manifest contains bytes that are not valid UTF-8: the file was opened with encoding='utf-8' and Python raised UnicodeDecodeError. The message includes the reason (e.g. 'invalid start byte') and the byte offset where decoding failed.

Solutions

  1. Reopen the file at the reported byte offset to find the offending character.
  2. Re-save the manifest as UTF-8 (editors: 'Save with encoding → UTF-8').
  3. Prefer ASCII-only manifest text to avoid encoding drift entirely.

Example fix

# before: description saved as Latin-1 containing 'café'
# after: re-save file with UTF-8 encoding
description: "café"
Defensive patterns

Strategy: validation

Validate before calling

try:
    open(manifest_path, encoding="utf-8").read()
except UnicodeDecodeError:
    raise SystemExit("manifest must be UTF-8; re-save with UTF-8 encoding")

Try / catch

except ValidationError as e:
    if "not valid UTF-8" in str(e):
        transcode_to_utf8(path)  # read as detected legacy encoding, rewrite as UTF-8

Prevention

When it happens

Trigger: Manifest was saved in a legacy 8-bit encoding (Latin-1, Windows-1252) or contains binary garbage; open(..., encoding='utf-8') fails at the reported byte offset.

Common situations: Editing the manifest in an editor that saved as ANSI/Latin-1 (common on Windows with non-ASCII characters in the description); copy-pasting text with a stray BOM-less non-UTF8 byte; a binary file accidentally placed at the manifest path.

Related errors


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

Appendix: source

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

        Raises:
            ValidationError: If manifest is invalid
        """
        self.path = manifest_path
        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

View on GitHub (pinned to bf88c9f9a8)