HKUDS/DeepTutor · error · HTTPException

'{sanitized_filename}' is not a valid zip archive.

Error message

'{sanitized_filename}' is not a valid zip archive.

What it means

Raised by _save_zip_archive when Python's zipfile module throws BadZipFile while opening/extracting an uploaded archive. The file's name/extension suggests a .zip but its content is corrupt, truncated, or not a zip at all (e.g. a renamed file or an interrupted upload). The router converts it to HTTP 400 so the client knows the payload itself is invalid.

Source

Thrown at deeptutor/api/routers/knowledge.py:290

                        status_code=400,
                        detail=(
                            f"Archive '{sanitized_filename}' exceeds maximum size limit of "
                            f"{format_bytes_human_readable(max_size)}"
                        ),
                    )
                tmp.write(chunk)

        try:
            result = safe_extract_zip(
                tmp_path, target_dir, allowed_extensions=allowed_extensions or set()
            )
        except ArchiveTooLargeError as exc:
            raise HTTPException(
                status_code=400,
                detail=f"Rejected archive '{sanitized_filename}': {exc}",
            ) from exc
        except zipfile.BadZipFile as exc:
            raise HTTPException(
                status_code=400,
                detail=f"'{sanitized_filename}' is not a valid zip archive.",
            ) from exc

        if not result.extracted:
            raise HTTPException(
                status_code=400,
                detail=f"Archive '{sanitized_filename}' contained no supported files.",
            )
        return result.extracted
    finally:
        if tmp_path is not None:
            tmp_path.unlink(missing_ok=True)


# Folder organization is purely a human-facing layout: folders are real
# subdirectories under ``raw/`` (no manifest, no retrieval effect). These
# helpers keep user-supplied relative paths safe before they touch the FS.

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Re-download or regenerate the archive and verify it opens locally with `unzip -t file.zip`
  2. Check the upload pipeline (proxy body limits, multipart handling) is not truncating the file
  3. If the file is not meant to be an archive, upload it with its real extension so it bypasses zip handling
  4. Verify Content-Length matches the actual file size before uploading

Example fix

# before
files = {'file': open('notes.zip','rb')}  # notes.zip is actually a PDF
requests.post(url, files=files)
# after
import zipfile
with open('notes.zip','rb') as f:
    assert zipfile.is_zipfile(f), 'not a zip'
requests.post(url, files=files)
Defensive patterns

Strategy: validation

Validate before calling

import zipfile

def is_valid_zip(path):
    with open(path,'rb') as f:
        return zipfile.is_zipfile(f) and zipfile.ZipFile(f).testzip() is None

Try / catch

try: resp = upload(files)
except HTTPError as e:
    if e.response.status_code == 400 and 'not a valid zip archive' in e.response.text(): repair_and_retry()
    else: raise

Prevention

When it happens

Trigger: POST to the knowledge-base upload endpoint with a file whose extension triggers zip handling but whose bytes fail zipfile.ZipFile parsing — corrupt download, HTML error page saved as .zip, multipart upload truncated by a proxy, or double-compressed/encrypted archive.

Common situations: Client uploads a file renamed to .zip; archive corrupted during transfer; a 0-byte zip from a failed disk write; test fixtures generating invalid zips.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/5279b92ca0331d1c. Report an issue: GitHub.