github/spec-kit · error · ValidationError
No extension.yml found in archive
Error message
No extension.yml found in archive
What it means
Thrown by ExtensionManager.install_from_zip after extracting an archive to a temp directory: neither the extraction root nor the single top-level subdirectory contains an extension.yml manifest. The installer only looks one level deep, so a manifest nested further down (or absent entirely) is treated as an invalid extension package.
Source
Thrown at src/specify_cli/extensions/__init__.py:2723
archive_file=archive_file,
source_name=source_name,
content_type=content_type,
error_type=ValidationError,
)
# Find extension directory (may be nested)
extension_dir = temp_path
manifest_path = extension_dir / "extension.yml"
# Check if manifest is in a subdirectory
if not manifest_path.exists():
subdirs = [d for d in temp_path.iterdir() if d.is_dir()]
if len(subdirs) == 1:
extension_dir = subdirs[0]
manifest_path = extension_dir / "extension.yml"
if not manifest_path.exists():
raise ValidationError("No extension.yml found in archive")
# Install from extracted directory
return self.install_from_directory(
extension_dir, speckit_version, priority=priority, force=force
)
def _config_root_is_contained(self, specify_dir: Path) -> bool:
"""Report whether `.specify` is a real directory inside the project.
Checked component by component so a symlink anywhere on the path is
rejected before it becomes the containment root. A missing `.specify`
is fine: scaffolding creates it under the project root.
"""
try:
root = self.project_root.resolve()
except OSError:
return False
current = self.project_rootView on GitHub (pinned to bf88c9f9a8)
Solutions
- Rebuild the archive so extension.yml sits at the root or inside exactly one top-level directory: `cd my-ext && zip -r ../my-ext.zip .`
- Inspect the archive layout first: `unzip -l my-ext.zip` or `tar -tzf my-ext.tar.gz` and confirm the manifest's depth
- If nesting is unavoidable, extract locally and install from the directory instead (install_from_directory), pointing at the folder that holds extension.yml
- If packaging via GitHub 'Source code' archives, add a release artifact or CI step that repacks with the manifest at the root
Example fix
# before: zip created from parent directory zip -r my-ext.zip my-ext/ # root = my-ext/, extension.yml inside -> OK only if single dir # problem: multiple dirs at root zip -r bundle.zip ext/ docs/ tests/ # root has 3 dirs, manifest not found # after: single top-level dir containing the manifest, or manifest at root cd my-ext && zip -r ../my-ext.zip .
Defensive patterns
Strategy: validation
Validate before calling
import zipfile, tarfile
from pathlib import Path
def archive_has_root_manifest(path: Path) -> bool:
"""True if extension.yml is at archive root or its single top-level dir."""
names = []
if zipfile.is_zipfile(path):
with zipfile.ZipFile(path) as z:
names = z.namelist()
elif tarfile.is_tarfile(path):
with tarfile.open(path) as t:
names = t.getnames()
else:
return False
tops = {n.split('/')[0] for n in names if n.strip()}
return 'extension.yml' in names or (
len(tops) == 1 and f'{next(iter(tops))}/extension.yml' in names
)
assert archive_has_root_manifest(Path('my-ext.zip')) Try / catch
from specify_cli.extensions import ExtensionError
try:
manager.install_from_zip(archive, speckit_version)
except ExtensionError as e:
if 'No extension.yml found' in str(e):
# repackage with manifest at root, or install from directory
... Prevention
- Standardize extension packaging: manifest at archive root or one top-level dir
- Add a CI packaging step that asserts archive_has_root_manifest before publishing
When it happens
Trigger: Calling install_from_zip (directly or via `specify extension install <path-or-url>` on a .zip/.tar.gz) where the archive has no extension.yml at its root and either has multiple top-level directories or a single subdir that also lacks extension.yml.
Common situations: Zipping the parent workspace folder instead of the extension package; an archive with multiple nested wrappers (dist/my-ext-v1.0/my-ext/extension.yml); downloading a source tarball from GitHub whose root is a repo folder plus .github, tests, etc.; forgetting to include the manifest at all.
Related errors
- Artifact '{candidate}' does not contain a bundle.yml.
- Downloaded artifact for bundle '{entry_id}' from {_source_de
- No extension.yml found in {source_path}
- Extension '{resolved_id}' is bundled with spec-kit but not f
- Invalid YAML in {path}: {e}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/650c01d0fa878f71.
Report an issue: GitHub.