github/spec-kit · error · ExtensionError

Could not install extension from downloaded archive: {exc}

Error message

Could not install extension from downloaded archive: {exc}

What it means

The archive passed format detection, but manager.install_from_zip raised a plain OSError during extraction or installation (the ExtensionError paths of install_from_zip propagate as-is; only OSError gets this wrapper). This is a filesystem-level failure during unpacking or copying into .specify/extensions — permissions, disk space, path length, or exotic archive member metadata.

Source

Thrown at src/specify_cli/extensions/_commands.py:217

            raise ExtensionError(
                f"{url} did not return a ZIP archive or tar.gz/tgz archive "
                f"(got {len(archive_data)} bytes). This usually means the request "
                "was not authenticated and a login/HTML page was returned. "
                "Verify the URL and configured credentials."
            ) from exc

        # Consume the transient inode reserved above rather than reopening the
        # cache pathname during extraction.
        try:
            return manager.install_from_zip(
                archive_path,
                speckit_version,
                priority=priority,
                force=force,
                archive_file=download_file,
            )
        except OSError as exc:
            raise ExtensionError(
                f"Could not install extension from downloaded archive: {exc}"
            ) from exc
    finally:
        if download_file is not None:
            try:
                download_file.close()
            except OSError:
                pass
        elif download_fd >= 0:
            try:
                os.close(download_fd)
            except OSError:
                pass


def _load_catalog_command_config(project_root: Path, config_path: Path) -> dict:
    """Load extension catalog CLI config with user-facing shape errors."""
    try:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Read the chained cause (`exc.__cause__`) — the errno pinpoints ENOSPC vs EACCES vs anything else
  2. Free disk space (extraction roughly doubles the archive footprint)
  3. Fix permissions on the project/.specify tree so extraction and copy can write
  4. On Windows, enable long-path support or move the project shallower if errno relates to path length
  5. Repackage the extension without unusual entries (absolute paths, symlinks to devices) and retry
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil
from pathlib import Path

def room_to_extract(project_root: Path, archive: Path) -> bool:
    need = archive.stat().st_size * 2
    return shutil.disk_usage(project_root).free > need

Try / catch

from specify_cli.extensions import ExtensionError

try:
    install_from_url_cmd(project_root, url, speckit_version)
except ExtensionError as e:
    if 'Could not install extension from downloaded archive' in str(e):
        cause = e.__cause__  # OSError errno tells: ENOSPC, EACCES, path length...

Prevention

When it happens

Trigger: Thrown at src/specify_cli/extensions/_commands.py:217 when the library encounters an invalid state.

Common situations: Disk filling up while extracting a large extension; read-only or permission-restricted .specify; archives containing absolute paths or device entries that the extractor's safe-copy layer struggles with; long paths on Windows.

Related errors


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