django/django · error · CommandError

couldn't extract file %s to %s: %s

Error message

couldn't extract file %s to %s: %s

What it means

A CommandError raised by TemplateCommand.extract when `django.utils.archive.extract(filename, tempdir)` raises ArchiveException or OSError. The downloaded/copied file is not a recognized, well-formed archive (zip, tar, tar.gz, etc.).

Source

Thrown at django/core/management/templates.py:380

            ext = base[-4:] + ext
            base = base[:-4]
        return base, ext

    def extract(self, filename):
        """
        Extract the given file to a temporary directory and return
        the path of the directory with the extracted content.
        """
        prefix = "django_%s_template_" % self.app_or_project
        tempdir = tempfile.mkdtemp(prefix=prefix, suffix="_extract")
        self.paths_to_remove.append(tempdir)
        if self.verbosity >= 2:
            self.stdout.write("Extracting %s" % filename)
        try:
            archive.extract(filename, tempdir)
            return tempdir
        except (archive.ArchiveException, OSError) as e:
            raise CommandError(
                "couldn't extract file %s to %s: %s" % (filename, tempdir, e)
            )

    def is_url(self, template):
        """Return True if the name looks like a URL."""
        if ":" not in template:
            return False
        scheme = template.split(":", 1)[0].lower()
        return scheme in self.url_schemes

    def apply_umask(self, old_path, new_path):
        current_umask = os.umask(0)
        os.umask(current_umask)
        current_mode = stat.S_IMODE(os.stat(old_path).st_mode)
        os.chmod(new_path, current_mode & ~current_umask)

    def make_writeable(self, filename):
        """

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Confirm the file is a real archive: `file template.zip` should report Zip or gzip/tar data.
  2. Re-download the template (the file may be truncated).
  3. Repackage as .zip or .tar.gz, which django.utils.archive supports.
  4. If you only have a directory of templates, point --template at the directory path directly (handle_template returns dirs without extracting).

Example fix

# before
django-admin startproject myproj --template=https://example.com/readme.md
# after
django-admin startproject myproj --template=https://example.com/template.zip
Defensive patterns

Strategy: validation

Validate before calling

import zipfile, tarfile

def looks_like_archive(path: str) -> bool:
    try:
        if zipfile.is_zipfile(path):
            return True
        if tarfile.is_tarfile(path):
            return True
    except OSError:
        pass
    return False

Try / catch

from django.core.management.base import CommandError
try:
    call_command('startproject', name, template=path)
except CommandError as e:
    if 'couldn't extract' in str(e):
        logger.error('Template %s is not a valid zip/tar archive', path)
        sys.exit(1)
    raise

Prevention

When it happens

Trigger: Passing `--template=notes.txt` (plain file, not an archive), a truncated/corrupted .zip from an interrupted download, or an archive type not supported by django.utils.archive.

Common situations: Pointing --template at a single template file instead of an archive, GitHub 'raw' URLs that return HTML, partial downloads, or .rar/.7z archives (unsupported).

Related errors


AI-assisted analysis of django/django@ae25a40be0 (2026-08-06). Data as JSON: /api/errors/23765d56b6de4bec. Report an issue: GitHub.