zylon-ai/private-gpt · error · SkillDomainError
EMPTY_ZIP
EMPTY_ZIP
Error message
ZIP file cannot be empty
What it means
SkillDomainError with code EMPTY_ZIP: _extract_zip raises this when the opened archive has no non-directory members, or all members have file_size == 0. It distinguishes 'structurally valid but contentless' archives from corrupt ones (INVALID_ZIP), so the user gets an actionable message.
Source
Thrown at private_gpt/server/skills/skills_files.py:167
filename = f"{field_name.rstrip('[]')}{ext}"
return filename, mime
def _is_zip(upload: UploadFile) -> bool:
filename = (upload.filename or "").lower()
content_type = (upload.content_type or "").lower()
return filename.endswith(".zip") or content_type in {
"application/zip",
"application/x-zip-compressed",
}
def _extract_zip(upload: UploadFile, payload: bytes) -> list[tuple[str, bytes]]:
try:
with zipfile.ZipFile(io.BytesIO(payload)) as archive:
members = [item for item in archive.infolist() if not item.is_dir()]
if not members or all(item.file_size == 0 for item in members):
raise SkillDomainError(
SkillErrorCode.EMPTY_ZIP, "ZIP file cannot be empty"
)
raw_entries = [
(item.filename, archive.read(item.filename)) for item in members
]
return _flatten_wrapper_directory(raw_entries)
except SkillDomainError as e:
raise e
except Exception as exc:
raise SkillDomainError(
SkillErrorCode.INVALID_ZIP,
f"Invalid ZIP file: {upload.filename or 'unnamed.zip'}",
) from exc
def _flatten_wrapper_directory(
entries: list[tuple[str, bytes]],View on GitHub (pinned to 4a030776a3)
Solutions
- Inspect the archive (`unzip -l out.zip`) to confirm it has non-empty file members.
- Re-run the packaging step after verifying the source directory actually contains the built files (SKILL.md etc.).
- Add a pre-upload check that the zip has at least one member with size > 0.
- If a download produced the zip, verify its size/checksum before packaging.
Example fix
# before
import zipfile
zf = zipfile.ZipFile('out.zip', 'w')
zf.close() # empty archive -> EMPTY_ZIP on upload
# after
zf = zipfile.ZipFile('out.zip', 'w')
zf.write('SKILL.md')
zf.close() Defensive patterns
Strategy: validation
Validate before calling
import zipfile
def zip_has_content(path: str) -> bool:
with zipfile.ZipFile(path) as zf:
return any(not i.is_dir() and i.file_size > 0 for i in zf.infolist()) Type guard
const zipHasContent = (infos: { name: string; dir: boolean; size: number }[]): boolean =>
infos.some((i) => !i.dir && i.size > 0); Prevention
- Assert a non-empty member list after any packaging step in CI.
- Verify source files exist and are non-empty before zipping.
- Check downloaded artifacts' sizes before repackaging.
When it happens
Trigger: Uploading a zip that contains only directory entries; a zip whose every file member is zero bytes (e.g. created by `zip -r out.zip emptydir` or by a failed build step that touched empty files); a placeholder zip committed to make a form valid.
Common situations: CI artifacts produced before compilation/copy steps ran; zipping an empty staging directory when upstream download failed silently; `touch`-based stubs in test data; disk-full during archive creation truncating contents to headers only.
Related errors
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/0e694a6cc1a30ede.
Report an issue: GitHub.