langflow-ai/langflow · error · ValueError
Uploaded file is not a valid ZIP archive: {exc}
Error message
Uploaded file is not a valid ZIP archive: {exc} What it means
Raised by _extract_flows_sync in zip_utils.py when zipfile.ZipFile cannot parse the uploaded bytes — Python raises zipfile.BadZipFile for corrupt, truncated, or non-ZIP content, and the helper converts it to ValueError with this message. The flows-import endpoint catches it and returns a 4xx to the client. It means the bytes received were not a readable ZIP archive.
Source
Thrown at src/backend/base/langflow/api/utils/zip_utils.py:38
"""Result of synchronous ZIP extraction, including warnings to log after."""
flows: list[dict] = field(default_factory=list)
warnings: list[str] = field(default_factory=list)
def _extract_flows_sync(contents: bytes) -> _ZipExtractionResult:
"""Synchronous helper that performs all blocking ZIP I/O.
Raises:
ValueError: If the ZIP is corrupt or contains more than MAX_ZIP_ENTRIES JSON files.
"""
result = _ZipExtractionResult()
try:
zf = zipfile.ZipFile(io.BytesIO(contents), "r")
except zipfile.BadZipFile as exc:
msg = f"Uploaded file is not a valid ZIP archive: {exc}"
raise ValueError(msg) from exc
with zf:
json_entries = [info for info in zf.infolist() if info.filename.lower().endswith(".json")]
if len(json_entries) > MAX_ZIP_ENTRIES:
msg = f"ZIP contains {len(json_entries)} JSON entries, exceeding the limit of {MAX_ZIP_ENTRIES}"
raise ValueError(msg)
for info in json_entries:
if info.file_size > MAX_ENTRY_UNCOMPRESSED_BYTES:
result.warnings.append(
f"Skipping ZIP entry '{info.filename}': uncompressed size "
f"{info.file_size} exceeds limit of {MAX_ENTRY_UNCOMPRESSED_BYTES} bytes"
)
continue
try:
raw = zf.read(info.filename)
if len(raw) > MAX_ENTRY_UNCOMPRESSED_BYTES:View on GitHub (pinned to 976ec789d2)
Solutions
- Confirm the uploaded file actually is a ZIP (unzip -t file.zip locally) and re-export a real ZIP bundle
- If you have a single .json flow, use the JSON import endpoint or wrap it: zip flows.zip flow.json
- Check for proxy/upload truncation: compare the file size/hash before upload vs on the server
- Verify the multipart field name and filename match what the endpoint expects (with .zip extension)
Example fix
# before curl -F "file=@myflow.json" /api/v1/flows/upload/ # after curl -F "file=@flows.zip" /api/v1/flows/upload/
Defensive patterns
Strategy: validation
Validate before calling
import zipfile, io
def is_valid_flow_zip(path: str) -> bool:
try:
with zipfile.ZipFile(path) as zf:
return zf.testzip() is None
except zipfile.BadZipFile:
return False Try / catch
try:
result = import_flows(zip_bytes)
except ValueError as e:
if "not a valid ZIP archive" in str(e):
if looks_like_json(zip_bytes):
result = import_flow_json(zip_bytes) # single-flow fallback path
else:
raise
else:
raise Prevention
- Validate with zipfile.ZipFile locally before every upload
- Export ZIP bundles from the UI's bulk-export action, not single-flow JSON downloads
- Compare file size before/after transfer to catch proxy truncation
When it happens
Trigger: POST /api/v1/flows/upload/ (or any flows-import route using _extract_flows_sync) with a file that is not a ZIP: a bare .json flow file, a .tar.gz, a text file, or a ZIP truncated by a proxy/upload limit mid-transfer.
Common situations: Exporting a single flow from the Langflow UI (which downloads JSON, not ZIP) and re-uploading it directly; client-side encoding setting the wrong multipart field name so the server reads a different part; uploads truncated by nginx client_max_body_size or similar proxies.
Related errors
- ZIP contains {len(json_entries)} JSON entries, exceeding the
- Failed to install MCP
- Invalid flow data
- Deployment name is required
- Invalid JSON format.
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/13fbfef5546dfb62.
Report an issue: GitHub.