Directories within Spaces where users have write permissions are quite limited. Directories starting with a period (.) or those directly under the root directory are almost impossible. They may also be inaccessible. It’s best to assume you can’t use directories outside the user home directory. (There are some exceptions as noted below…)
Root cause: your code tries to create ./hf_cache under the app repo at runtime. In Spaces the runtime user often cannot write to the repo/workdir. Use a writable absolute path: /data if you enabled Persistent storage, else /tmp. Redirect Hugging Face caches or pass cache_dir to hf_hub_download. This is a permissions/layout issue, not hardware. (Hugging Face)
What’s happening (background + context)
-
Spaces storage layout. Your code runs inside a container. Persistent disk, when enabled, is mounted at
/dataand is writable. Other paths may be read-only or owned by a different user. (Hugging Face) -
Runtime user. Docker Spaces run as UID
1000. If your repo files are owned byrootor your code writes relative to.(repo checkout), writes can fail with[Errno 13]. (Hugging Face) -
HF caching defaults.
huggingface_huband related libs write under~/.cache/huggingfaceunless you override withHF_HOME,HF_HUB_CACHE,TRANSFORMERS_CACHE, etc., or passcache_dirtohf_hub_download. If that default resolves to an unwritable place, you get a PermissionError. (Hugging Face) -
Seen in the wild. Multiple forum threads report identical PermissionErrors in Spaces fixed by pointing caches to a writable dir like
/dataor/tmp. Dates: 2023-07-13, 2024-05-19, 2025-03-22. (Hugging Face Forums)
Fast, safe fix (no Docker changes)
-
Enable Persistent storage in your Space settings. This gives you
/datathat survives restarts. If you skip this, use/tmpwhich is ephemeral. (Hugging Face) -
Set env vars in the Space → Settings → Variables so all HF libs write under
/data:
HF_HOME=/data/.huggingface
HF_HUB_CACHE=/data/.cache/huggingface/hub
TRANSFORMERS_CACHE=/data/.cache/huggingface/transformers
HF_DATASETS_CACHE=/data/.cache/huggingface/datasets
These are the officially supported knobs. They redirect all downloads, snapshots, and token files. (Hugging Face)
- Change your code to stop writing
./hf_cache. Use an absolute, writable cache root, prefer/data, fall back to/tmp:
# refs:
# - HF env vars: https://huggingface.co/docs/huggingface_hub/en/package_reference/environment_variables
# - Cache dir param: https://huggingface.co/docs/huggingface_hub/en/guides/download
import os, pathlib
from huggingface_hub import hf_hub_download
# honor env if provided; otherwise choose a writable default
cache_root = (
os.getenv("HF_HUB_CACHE")
or ("/data/hf_cache" if os.path.isdir("/data") else "/tmp/hf_cache")
)
pathlib.Path(cache_root).mkdir(parents=True, exist_ok=True)
model_path = hf_hub_download(
repo_id="your/repo",
filename="yourfile.bin",
cache_dir=cache_root, # absolute and writable
)
Passing cache_dir is supported and recommended when you control the path. (Hugging Face)
-
Defer downloads until app startup instead of at import time. Your stack trace shows a download during module import. Failures there kill the process before the server starts. Do the download in an app “startup” hook or first-request path. (Hugging Face)
-
Quick sanity check to verify writability:
import os, pathlib
p = pathlib.Path(os.getenv("HF_HUB_CACHE", "/data/.cache/huggingface/hub"))
print(p, "exists:", p.exists(), "writable:", os.access(p, os.W_OK))
If writable is False, switch to /tmp/... or fix Docker user/ownership. (Hugging Face)
If you are using a Docker Space
Match the runtime user and set caches to /data. This avoids permission flips between build-time root and run-time UID 1000.
# refs:
# - Docker Spaces permissions: https://huggingface.co/docs/hub/en/spaces-sdks-docker
# - First Docker Space guide: https://huggingface.co/docs/hub/en/spaces-sdks-docker-first-demo
RUN useradd -m -u 1000 user
USER user
ENV HOME=/home/user PATH=/home/user/.local/bin:$PATH
WORKDIR $HOME/app
COPY --chown=user . $HOME/app
# put HF caches on the persistent volume if enabled
ENV HF_HOME=/data/.huggingface \
HF_HUB_CACHE=/data/.cache/huggingface/hub \
TRANSFORMERS_CACHE=/data/.cache/huggingface/transformers
These lines mirror the official guidance and fix typical [Errno 13] cache errors. (Hugging Face)
Why this solves it
-
/datais the documented persistent, writable mount for Spaces. Redirecting caches there removes permission failures and keeps downloads across restarts. (Hugging Face) -
hf_hub_download(cache_dir=...)andHF_*env vars are the supported ways to move caches. They exist for containerized runtimes like Spaces. (Hugging Face) -
UID
1000at runtime plus root-owned files during build causes write failures unless you set the user and ownership properly. The docs warn about this. (Hugging Face)
Common pitfalls to avoid
-
Writing under
.or~without confirming ownership. Use absolute paths. (Hugging Face) -
Assuming caches persist in
/tmp. They vanish on restart. Prefer/dataif you need persistence. (Hugging Face) -
Changing file permissions to 777 in containers. This can mask the real problem and still fail under UID 1000 on redeploy. Move caches instead. Background discussion exists, but official guidance is to set caches and user. (Stack Overflow)
Short reference set (checked Oct 11, 2025)
-
Spaces persistent storage:
/datamount, persists across restarts. (Hugging Face) -
HF cache control:
HF_HOME,HF_HUB_CACHE,cache_dirinhf_hub_download. (Hugging Face) -
Docker Spaces permissions: runtime UID 1000, set user, WORKDIR, ownership. (Hugging Face)
-
Similar issues and fixes: forum threads confirming permission-denied symptoms and
/dataor env-var fixes. (Hugging Face Forums)
If you enable storage and apply the env vars, your current PermissionError: './hf_cache' will stop. If you want, share the exact repo snippet where hf_hub_download is called and I’ll show the minimal diff to adopt /data or /tmp.