crewAIInc/crewAI · error · SystemExit

Downloaded archive is empty.

Error message

Downloaded archive is empty.

What it means

Raised by RemoteTemplateManager._extract_zip() when the downloaded GitHub zipball opens as a valid zip but contains zero entries (zf.namelist() is empty). It is a data-integrity guard before any files are written. The CLI prints the red message and exits 1; an empty destination directory may already have been created by a prior branch but no content is extracted.

Source

Thrown at lib/cli/src/crewai_cli/remote_template/main.py:225

        """Download the default branch zipball for a repo."""
        url = f"{GITHUB_API_BASE}/repos/{GITHUB_ORG}/{repo_name}/zipball"
        try:
            response = httpx.get(url, follow_redirects=True, timeout=60)
            response.raise_for_status()
        except httpx.HTTPError as e:
            click.secho(f"Failed to download template: {e}", fg="red")
            raise SystemExit(1) from e

        return response.content

    def _extract_zip(self, zip_bytes: bytes, dest: str) -> None:
        """Extract a GitHub zipball into dest, stripping the top-level directory."""
        with zipfile.ZipFile(io.BytesIO(zip_bytes)) as zf:
            # GitHub zipballs have a single top-level dir like 'crewAIInc-fde-template_xxx-<sha>/'
            members = zf.namelist()
            if not members:
                click.secho("Downloaded archive is empty.", fg="red")
                raise SystemExit(1)

            top_dir = members[0].split("/")[0] + "/"

            os.makedirs(dest, exist_ok=True)

            for member in members:
                if member == top_dir or not member.startswith(top_dir):
                    continue

                relative_path = member[len(top_dir) :]
                if not relative_path:
                    continue

                target = os.path.realpath(os.path.join(dest, relative_path))
                if not target.startswith(
                    os.path.realpath(dest) + os.sep
                ) and target != os.path.realpath(dest):
                    continue

View on GitHub (pinned to 754d7323be)

Solutions

  1. Re-run `crewai template add <name>` — an empty archive is almost always a corrupted transfer.
  2. If it repeats, download the zip manually (curl -L from github.com/crewAIInc/<repo>/archive/...) and verify `unzip -l` shows files.
  3. Bypass or configure the intercepting proxy/AV if manual downloads are also empty.
  4. Report upstream if the repo's default branch is genuinely empty on GitHub.
Defensive patterns

Strategy: validation

Validate before calling

import io, zipfile

def is_usable_zipball(data: bytes) -> bool:
    try:
        with zipfile.ZipFile(io.BytesIO(data)) as zf:
            return len(zf.namelist()) > 0
    except zipfile.BadZipFile:
        return False

Prevention

When it happens

Trigger: The zipball HTTP body was truncated or replaced by an empty/intercepted 200 response (transparent proxy, captive portal) that still decompresses as a zip; extremely rare GitHub-side artifact corruption. Genuine GitHub zipballs always contain at least the top-level directory entry.

Common situations: Corporate proxies mangling binary downloads; anti-virus stripping archive contents; flaky connections yielding a short body that happens to parse as an empty zip.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/ea8dc519a107f4f8. Report an issue: GitHub.