{"record":{"id":"755c8a19f4adb71b","repo":"HKUDS/DeepTutor","slug":"archive-sanitized-filename-contained-no-suppor","errorCode":null,"errorMessage":"Archive '{sanitized_filename}' contained no supported files.","messagePattern":"Archive '(.+?)' contained no supported files\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/knowledge.py","lineNumber":296,"sourceCode":"                tmp.write(chunk)\n\n        try:\n            result = safe_extract_zip(\n                tmp_path, target_dir, allowed_extensions=allowed_extensions or set()\n            )\n        except ArchiveTooLargeError as exc:\n            raise HTTPException(\n                status_code=400,\n                detail=f\"Rejected archive '{sanitized_filename}': {exc}\",\n            ) from exc\n        except zipfile.BadZipFile as exc:\n            raise HTTPException(\n                status_code=400,\n                detail=f\"'{sanitized_filename}' is not a valid zip archive.\",\n            ) from exc\n\n        if not result.extracted:\n            raise HTTPException(\n                status_code=400,\n                detail=f\"Archive '{sanitized_filename}' contained no supported files.\",\n            )\n        return result.extracted\n    finally:\n        if tmp_path is not None:\n            tmp_path.unlink(missing_ok=True)\n\n\n# Folder organization is purely a human-facing layout: folders are real\n# subdirectories under ``raw/`` (no manifest, no retrieval effect). These\n# helpers keep user-supplied relative paths safe before they touch the FS.\n_BAD_PATH_CHARS = re.compile(r'[\\\\:*?\"<>|\\x00-\\x1f]')\n\n\ndef _sanitize_path_segment(segment: str) -> str:\n    \"\"\"Sanitize a single folder/file path segment for safe FS use.\"\"\"\n    cleaned = _BAD_PATH_CHARS.sub(\"\", segment).strip().strip(\".\")","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/knowledge.py#L278-L314","documentation":"Raised by _save_zip_archive after a zip was successfully opened and extracted, but result.extracted was empty — no member of the archive matched the knowledge base's supported file extensions. It is a content-level rejection distinct from a corrupt archive (error 140).","triggerScenarios":"Uploading a .zip that contains only unsupported files (e.g. .exe, .png, .txt when only document extensions are supported), or a zip whose supported members were all filtered out by size/path checks.","commonSituations":"User zips a folder of images or binaries expecting text extraction; nested zips where only the outer archive is inspected; supported files hidden in dot-directories that extraction skips.","solutions":["Inspect the archive (`unzip -l`) and confirm it contains files with the KB's supported extensions","Remove unsupported members and re-zip only the documents you want ingested","If you need a format supported, check the router's extension allow-list / provider format rules before uploading"],"exampleFix":"# before\nzip contents: photo1.png, photo2.png\n# after\nzip contents: lecture1.pdf, notes.md","handlingStrategy":"validation","validationCode":"SUPPORTED = {'.pdf','.md','.txt','.docx'}\n\ndef zip_has_supported(path):\n    with zipfile.ZipFile(path) as z:\n        return any(Path(n).suffix.lower() in SUPPORTED for n in z.namelist())","typeGuard":null,"tryCatchPattern":null,"preventionTips":["List zip members and intersect with the KB's supported extensions before upload","Bundle only ingestable documents in archive uploads"],"tags":["zip","upload","empty-result","http-400"],"backgroundTag":"unsupported-file-format","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}