fix(cache): fully remove downloaded models - #5395
Conversation
- Resolve nested cache symlinks recursively so ModelScope and Hugging Face payload files are removed instead of leaving real weights behind. - Preserve files referenced by another cached model and unlink local model_uri entries without touching user-managed source directories. - Restrict recursive directory deletion to Xinference-managed cache and tensorizer roots to prevent arbitrary path removal. - Prune empty Hub directories up to, but never including, each managed download root; stop when sibling models or residual files remain. - Delete linked files before cache trees and tolerate concurrent cleanup races while still reporting real deletion failures. - Treat a false cache-delete API result as an error in WebUI and add localized messages for English, Chinese, Japanese, and Korean. - Cover nested targets, shared blobs, local sources, unmanaged paths, and ModelScope parent pruning with focused worker tests.
There was a problem hiding this comment.
Code Review
This pull request improves the model cache deletion process in Xinference. On the frontend, it adds error handling and localized error messages when cache deletion fails. On the backend, it introduces safer cache cleanup mechanisms, including resolving nested symlinks, preserving shared model files, and pruning empty parent directories within managed download caches, backed by comprehensive unit tests. The review feedback highlights two key issues: first, an unexpected OSError during empty directory pruning could abort the deletion process midway and leave the cache tracker in an inconsistent state; second, using XDG_CACHE_HOME directly as the OpenMind cache root is risky as it could lead to pruning directories in the shared system-wide cache.
qinxuye
left a comment
There was a problem hiding this comment.
Two additional cache-deletion findings:
- record source paths when cache links fall back to regular file copies - include sibling cache manifests before deleting shared Hub payloads - traverse model_uri directory links read-only with cycle protection - cover copy cleanup, shared-copy retention, and model_uri blob reuse
- scope OpenMind cleanup to $XDG_CACHE_HOME/openmind/hub - keep tracker state consistent when optional parent pruning fails - cover OpenMind root preservation and EACCES cleanup failures
qinxuye
left a comment
There was a problem hiding this comment.
One cache-deletion safety issue remains:
- Reserve the internal manifest filename so downloaded repositories cannot inject cache metadata. - Reject symlinked, replaced, non-regular, and unsupported manifest files before parsing paths. - Confine manifest-derived deletion targets to configured Hugging Face, ModelScope, OpenMind, and CSGHub roots. - Add malicious-manifest regressions while preserving copy-fallback source cleanup.
Resolve nested cache symlinks recursively so ModelScope and Hugging Face payload files are removed instead of leaving real weights behind.
Preserve files referenced by another cached model and unlink local model_uri entries without touching user-managed source directories.
Restrict recursive directory deletion to Xinference-managed cache and tensorizer roots to prevent arbitrary path removal.
Prune empty Hub directories up to, but never including, each managed download root; stop when sibling models or residual files remain.
Delete linked files before cache trees and tolerate concurrent cleanup races while still reporting real deletion failures.
Treat a false cache-delete API result as an error in WebUI and add localized messages for English, Chinese, Japanese, and Korean.
Cover nested targets, shared blobs, local sources, unmanaged paths, and ModelScope parent pruning with focused worker tests.
Summary
symlinks.
model_urisources and unmanaged directories from beingremoved.
Root Cause
Xinference recursively mirrors downloaded Hub snapshots into its cache using
symlinks. However,
WorkerActor.list_deletable_models()only inspected thefirst directory level.
For models containing nested directories, deleting the cache removed the
Xinference symlinks but left most ModelScope or Hugging Face payload files on
disk. Disk space was therefore not reclaimed.
The WebUI also ignored a backend response containing
result: falseand alwaysdisplayed a successful deletion notification.
This behavior was not Docker-specific. It affected Docker, local, and virtual
environment deployments; bind-mounted Docker storage only made the remaining
files easier to observe.
Changes
Backend
symlinks.
model_uriand unlink only thecache entry.
XINFERENCE_CACHE_DIR.roots.
os.rmdirafter deleting downloadedfiles.
lock file, incomplete download, or other residual content.
modelsrootFor example:
After all files for this model are deleted, empty directories are removed up
through
ZhipuAI--GLM-Image, while themodelscope/modelsroot remains.WebUI
resultfield returned by the cache deletion API.Safety
model_urisource directories are never recursively deleted.os.rmdir, notshutil.rmtree.