github/spec-kit · error · BundlerError
Invalid YAML in bundle.yml inside '{candidate}': {exc}
Error message
Invalid YAML in bundle.yml inside '{candidate}': {exc} What it means
The zip branch parses bundle.yml inline with yaml.safe_load; a YAMLError (syntax error, bad indentation, duplicate keys per safe_load rules, tab characters) is converted to BundlerError. Without this wrap the raw YAMLError — neither ValueError nor OSError — would escape bundle_install()'s except BundlerError as a traceback, so this keeps error reporting on-contract.
Source
Thrown at src/specify_cli/commands/bundle/__init__.py:812
# treatment as yamlio.load_yaml: decode as UTF-8 explicitly —
# feeding PyYAML the byte stream would let its Reader auto-detect
# a UTF-16 BOM and accept a manifest the directory and bundle.yml
# sources reject.
try:
text = raw.decode("utf-8")
except UnicodeError as exc:
raise BundlerError(
f"Could not read bundle.yml inside '{candidate}': {exc}"
) from exc
try:
data = _yaml.safe_load(text)
except _yaml.YAMLError as exc:
# The sibling directory/bundle.yml branches reach YAML through
# load_yaml(), which turns a parse failure into a BundlerError. This
# branch parses inline, so without this it raises a raw YAMLError --
# neither a ValueError nor an OSError -- which escapes
# bundle_install()'s `except BundlerError` as a traceback.
raise BundlerError(
f"Invalid YAML in bundle.yml inside '{candidate}': {exc}"
) from exc
return BundleManifest.from_dict(data)
if candidate.name == "bundle.yml" or candidate.suffix in (".yml", ".yaml"):
return BundleManifest.from_file(candidate)
raise BundlerError(
f"'{candidate}' is not a recognised bundle source (.zip artifact, bundle "
"directory, or bundle.yml)."
)
def _resolve_manifest_path(path: Path | None) -> Path:
target = (path or Path.cwd()).resolve()
if target.is_dir():
target = target / "bundle.yml"
if not target.exists():View on GitHub (pinned to bf88c9f9a8)
Solutions
- Run a local syntax check: python -c "import yaml,sys; yaml.safe_load(open('bundle.yml'))" and fix the reported line/column.
- Replace tabs with spaces, quote values containing colons, and re-zip the artifact.
- Validate the manifest outside the zip first (specify bundle install ./my-bundle with the same file) to iterate faster.
Example fix
# before (bundle.yml, tab-indented) bundle: id: my-bundle # after bundle: id: my-bundle
Defensive patterns
Strategy: validation
Validate before calling
import yaml
text = open("bundle.yml", encoding="utf-8").read()
try:
yaml.safe_load(text)
except yaml.YAMLError as exc:
raise SystemExit(f"bundle.yml syntax error: {exc}") Type guard
def is_valid_yaml(text: str) -> bool:
import yaml
try:
yaml.safe_load(text)
return True
except yaml.YAMLError:
return False Try / catch
try:
manifest = _local_manifest_source(Path("bundle.zip"))
except BundlerError as exc:
if "Invalid YAML in bundle.yml" in str(exc):
# fix the reported line, re-zip, retry
... Prevention
- Lint bundle.yml with a YAML validator before zipping.
- Use spaces (never tabs) for indentation in authored manifests.
When it happens
Trigger: A bundle.yml inside a .zip with tab indentation, an unclosed quote/bracket, or malformed frontmatter; specify bundle install ./bundle.zip triggers the inline parse path.
Common situations: Tabs pasted from terminals, unquoted strings containing ':', flow-style lists with missing commas, hand-edited manifests zipped without validation.
Related errors
- Malformed catalog config at {path}: expected a mapping at th
- Malformed catalog config at {path}: 'catalogs' must be a lis
- Malformed catalog config at {path}: each catalog entry must
- Malformed catalog config at {config_path}: expected a mappin
- Malformed catalog config at {config_path}: 'catalogs' must b
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/817c944297cd6740.
Report an issue: GitHub.