Repository coordinates on Hugging Face are a mutable address, not a release identity. If a service downloads main during every cold start, two replicas launched on different days can receive different model files even though their configuration names the same repository. A warm cache may hide that drift until a new node starts during an outage.
A reliable boundary combines a full commit hash with an explicit file manifest. Resolve the branch while the Hub is reachable, download only the files the runtime needs from that commit, record their sizes and SHA-256 values, then make the same lookup with Hub traffic disabled. An empty-cache negative control should fail immediately rather than silently selecting another revision.
Developers and operators following this practical guide should be comfortable with a Linux shell and Python virtual environment. The reproduced lab ran on Debian 13 with Python 3.13.5 and huggingface_hub 1.27.0. It uses a public 412,386-byte test model, requires no token, changes no global Python package and removes only its marker-owned /tmp directory. Cache admission is not inference acceptance: the lab proves identity, file presence and byte integrity, not framework compatibility, GPU fit, model quality or application output.
The complete run produced four release signals: a full commit, an exact six-file plan, a manifest over 412,386 admitted bytes and an offline lookup that accepted those bytes. The companion empty-cache request failed closed. This is the evidence a build pipeline should evaluate before it spends time on framework loading or inference tests.
LAB_READY {"huggingface_hub":"1.27.0","python":"3.13.5","repo":"hf-internal-testing/tiny-random-BertModel"}
REVISION_RESOLVED {"resolved_commit":"fc08ad9cc33be9aef4f55cc80e16ef5ae3d5981c","requested_revision":"main"}
DOWNLOAD_PLAN {"bytes_to_download":412386,"file_count":6,"revision":"fc08ad9cc33be9aef4f55cc80e16ef5ae3d5981c"}
CACHE_ADMITTED {"file_count":6,"revision":"fc08ad9cc33be9aef4f55cc80e16ef5ae3d5981c","total_bytes":412386,"weight_sha256":"545d8feae7cdaa752dfcecd8d480928b31a0f7a0b494877c9ab5ddf504906703"}
Read those lines as an admission result, not a serving success report. The rest of the article builds the exact candidate that produced them, proves both sides of the offline boundary and then separates cache acceptance from the decisions required for production.
Four values often get collapsed into “the model version,” although they answer different questions:
hf-internal-testing/tiny-random-BertModel names where the project lives.main or a release tag is a ref that an owner may move.Pinning only a Python dependency does not freeze model content. Pinning only model content does not freeze Transformers, PyTorch, CUDA, tokenizer behavior or custom code. Treat those as separate release inputs and retain them in one deployment record.
Hugging Face’s current download guide says that downloads use the latest main revision by default and that commit-based downloads require the full-length hash. Baseten’s revision-pinning guidance connects that control to compatibility review, evaluation integrity and the extra risk of trust_remote_code=True.
Content-addressed release thinking also applies outside model hubs. Voxfor’s OCI platform-digest inspection shows why a mutable tag and an immutable manifest digest belong to different decisions. A model commit plays the identity role; the manifest created below proves which local bytes satisfy it.
“Download the model” is too vague for an admission gate. A serving stack may need weights, configuration, tokenizer vocabulary, tokenizer metadata, generation configuration, adapter files or custom Python modules. Filtering saves transfer and storage only when the allowlist matches the actual runtime.
This fixture declares six files: BERT configuration, PyTorch weights and four tokenizer assets. The first block creates the isolated environment, pins the current client used in the test and records its version. Run all seven tested blocks in one shell session, in order.
set -Eeuo pipefail
LAB_ROOT=/tmp/voxfor-hf-cache-146-lab
MARKER="$LAB_ROOT/.voxfor-hf-cache-146"
CACHE_ROOT="$LAB_ROOT/cache"
EMPTY_CACHE="$LAB_ROOT/empty-cache"
REPO_ID=hf-internal-testing/tiny-random-BertModel
PYTHON_BIN=$(command -v python3)
for dependency in "$PYTHON_BIN" find; do
test -n "$dependency"
done
if test -e "$LAB_ROOT"; then
test -f "$MARKER"
test "$(<"$MARKER")" = voxfor-hf-cache-146-v1
else
mkdir -m 700 "$LAB_ROOT"
printf '%s\n' voxfor-hf-cache-146-v1 > "$MARKER"
fi
"$PYTHON_BIN" -m venv "$LAB_ROOT/venv"
"$LAB_ROOT/venv/bin/python" -m pip install --disable-pip-version-check --quiet \
'huggingface_hub==1.27.0'
mkdir -m 700 -p "$CACHE_ROOT" "$EMPTY_CACHE"
"$LAB_ROOT/venv/bin/python" - <<'PY'
import huggingface_hub, json, platform
print("LAB_READY " + json.dumps({
"python": platform.python_version(),
"huggingface_hub": huggingface_hub.__version__,
"repo": "hf-internal-testing/tiny-random-BertModel",
}, sort_keys=True))
PY
Private or gated repositories need a read token during the online admission stage. Keep that secret outside the receipt and candidate cache. HF_TOKEN overrides a stored token, so production automation should inject it from its secret manager and avoid printing request headers or environment dumps.
Resolve a branch only once per candidate release. HfApi.model_info() returns the commit currently behind main; the block requires a full 40-character value and writes it to a local receipt. Every later operation reads that frozen value instead of resolving the branch again.
"$LAB_ROOT/venv/bin/python" - <<'PY'
import json
from huggingface_hub import HfApi
repo = "hf-internal-testing/tiny-random-BertModel"
info = HfApi().model_info(repo_id=repo, revision="main", files_metadata=True)
assert len(info.sha) == 40
receipt = {
"repo": repo,
"requested_revision": "main",
"resolved_commit": info.sha,
"last_modified": info.last_modified.isoformat(),
}
with open("/tmp/voxfor-hf-cache-146-lab/resolved.json", "w") as handle:
json.dump(receipt, handle, indent=2, sort_keys=True)
print("REVISION_RESOLVED " + json.dumps(receipt, sort_keys=True))
PY
The test resolved main to fc08ad9cc33be9aef4f55cc80e16ef5ae3d5981c, last modified on April 1, 2024. That date is not a quality claim. It only timestamps the repository state used in this reproducible fixture.
Do not place main back into a production deployment after recording the commit. A branch lookup during startup reintroduces network availability and release drift. If a model owner later moves or deletes a repository, an approved internal artifact store or registry may add availability control, but the copied object still needs the upstream commit and local manifest in its provenance.
The current client can dry-run snapshot_download() and report which allowlisted files would transfer. Use this before a multi-gigabyte production download to catch a misspelled pattern, unexpected format or storage estimate that exceeds the candidate volume. The allowlist must be reviewed before any transfer; the plan is evidence, not the admitted artifact.
"$LAB_ROOT/venv/bin/python" - <<'PY'
import json
from huggingface_hub import snapshot_download
root = "/tmp/voxfor-hf-cache-146-lab"
with open(f"{root}/resolved.json") as handle:
revision = json.load(handle)["resolved_commit"]
patterns = [
"config.json", "pytorch_model.bin", "special_tokens_map.json",
"tokenizer.json", "tokenizer_config.json", "vocab.txt",
]
plan = snapshot_download(
repo_id="hf-internal-testing/tiny-random-BertModel",
revision=revision,
cache_dir=f"{root}/cache",
allow_patterns=patterns,
dry_run=True,
)
receipt = {
"revision": revision,
"file_count": len(plan),
"bytes_to_download": sum(item.file_size for item in plan if item.will_download),
"files": sorted(item.filename for item in plan),
}
assert receipt["files"] == sorted(patterns)
with open(f"{root}/dry-run.json", "w") as handle:
json.dump(receipt, handle, indent=2, sort_keys=True)
print("DOWNLOAD_PLAN " + json.dumps(receipt, sort_keys=True))
PY
Admission performs the transfer at the frozen revision, requires the snapshot directory name to equal the commit and hashes the resolved content of each cached file. Hugging Face’s cache guide explains the refs, snapshots and shared blobs layout. Hash the file content rather than treating a symlink path or modification time as integrity evidence.
"$LAB_ROOT/venv/bin/python" - <<'PY'
import hashlib, json
from pathlib import Path
from huggingface_hub import snapshot_download
root = Path("/tmp/voxfor-hf-cache-146-lab")
revision = json.loads((root / "resolved.json").read_text())["resolved_commit"]
patterns = [
"config.json", "pytorch_model.bin", "special_tokens_map.json",
"tokenizer.json", "tokenizer_config.json", "vocab.txt",
]
snapshot = Path(snapshot_download(
repo_id="hf-internal-testing/tiny-random-BertModel",
revision=revision,
cache_dir=root / "cache",
allow_patterns=patterns,
))
assert snapshot.name == revision
manifest = []
for relative in sorted(patterns):
path = snapshot / relative
assert path.is_file()
digest = hashlib.sha256(path.read_bytes()).hexdigest()
manifest.append({"path": relative, "bytes": path.stat().st_size, "sha256": digest})
receipt = {
"repo": "hf-internal-testing/tiny-random-BertModel",
"revision": revision,
"snapshot": str(snapshot),
"file_count": len(manifest),
"total_bytes": sum(item["bytes"] for item in manifest),
"manifest": manifest,
}
(root / "admission-receipt.json").write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n")
print("CACHE_ADMITTED " + json.dumps({
"revision": revision,
"file_count": receipt["file_count"],
"total_bytes": receipt["total_bytes"],
"weight_sha256": next(item["sha256"] for item in manifest if item["path"] == "pytorch_model.bin"),
}, sort_keys=True))
PY
Production weights may use Git LFS or Xet-backed storage, and one model can publish several frameworks or quantizations. An allowlist that downloads every *.bin, *.safetensors, ONNX and tokenizer variant wastes capacity and can hand the runtime an ambiguous set. Select the format that the pinned runtime actually loads, then dry-run that declaration.
Offline proof must run in a fresh process because the library reads environment variables at import time. Hugging Face documents that HF_HUB_OFFLINE=1 prevents Hub HTTP calls, uses cached files and raises if the requested content is absent. local_files_only=True makes the API call’s intent explicit as well.
HF_HUB_OFFLINE=1 "$LAB_ROOT/venv/bin/python" - <<'PY'
import hashlib, json
from pathlib import Path
from huggingface_hub import snapshot_download
root = Path("/tmp/voxfor-hf-cache-146-lab")
receipt = json.loads((root / "admission-receipt.json").read_text())
patterns = [item["path"] for item in receipt["manifest"]]
snapshot = Path(snapshot_download(
repo_id=receipt["repo"],
revision=receipt["revision"],
cache_dir=root / "cache",
allow_patterns=patterns,
local_files_only=True,
))
assert snapshot.name == receipt["revision"]
for expected in receipt["manifest"]:
path = snapshot / expected["path"]
assert path.is_file()
assert path.stat().st_size == expected["bytes"]
assert hashlib.sha256(path.read_bytes()).hexdigest() == expected["sha256"]
print("OFFLINE_ACCEPTED " + json.dumps({
"revision": receipt["revision"],
"network_calls_allowed": False,
"manifest_matches": True,
"files_verified": len(receipt["manifest"]),
}, sort_keys=True))
PY
A positive result could still come from an accidentally warm developer cache. Point the same exact revision at a deliberately empty cache. The empty-cache exception is a required negative control: it proves that the admission gate does not fetch, fall back to main or choose an arbitrary local snapshot when the required bytes are missing.
HF_HUB_OFFLINE=1 "$LAB_ROOT/venv/bin/python" - <<'PY'
import json
from huggingface_hub import snapshot_download
root = "/tmp/voxfor-hf-cache-146-lab"
revision = json.load(open(f"{root}/resolved.json"))["resolved_commit"]
try:
snapshot_download(
repo_id="hf-internal-testing/tiny-random-BertModel",
revision=revision,
cache_dir=f"{root}/empty-cache",
allow_patterns=["config.json", "pytorch_model.bin"],
local_files_only=True,
)
except Exception as error:
assert error.__class__.__name__ in {"LocalEntryNotFoundError", "IncompleteSnapshotError"}
print("OFFLINE_MISS_REJECTED " + json.dumps({
"revision": revision,
"cache": "empty",
"error": error.__class__.__name__,
}, sort_keys=True))
else:
raise AssertionError("empty offline cache unexpectedly resolved")
PY
The candidate cache is ready for runtime testing when the offline process returns the exact recorded commit, all six declared paths match their saved byte counts and SHA-256 values, no Hub request is permitted, and the empty-cache control returns LocalEntryNotFoundError or IncompleteSnapshotError. The reproduced run reported OFFLINE_ACCEPTED with six verified files and rejected the empty cache with LocalEntryNotFoundError.
The cache gate deliberately stops before inference. Cache acceptance authorizes runtime testing, not production traffic. A real deployment must load the snapshot path with the exact framework and package lock that production uses, deserialize the intended weight format, construct its tokenizer or processor, allocate CPU/GPU memory and run known inputs. Runpod’s cached-model guide demonstrates HF_HUB_OFFLINE, TRANSFORMERS_OFFLINE and local_files_only=True in a worker, but its example follows refs/main and can fall back to the first available snapshot. Replace that selection with the admitted commit path.
Resource proof comes next. Use GPU memory planning for local LLM inference to budget weights, KV cache, temporary workspace and concurrency. If layers land on CPU despite a visible GPU, run Ollama CPU-fallback diagnosis against the deployed runtime rather than blaming the Hub cache.
Serving capacity also changes independently of model identity. Before raising concurrency on an admitted model, consult vLLM KV-cache capacity workflow so successful weight loading is not mistaken for a safe latency envelope.
Remote code needs an even narrower policy. A pinned commit prevents code from changing beneath the deployment, but it does not make that code trustworthy. Review the exact files, prefer native library implementations, isolate the build and runtime, and do not pass secrets to untrusted model code. A mirror improves availability and governance only when provenance remains intact.
Never update a shared production cache in place. Build the next commit in a candidate path, generate a fresh manifest, run the offline cache gate, execute framework loading and application acceptance, then switch a versioned pointer or immutable deployment reference. Keep the previously accepted cache available until the new workload proves healthy.
Quality evaluation must use the same frozen revision recorded by deployment. For a retrieval application, apply RAG retrieval regression gate before promotion so a new model cannot pass on aggregate improvement while losing a must-pass query. Generative services need their own reviewed prompts, safety cases, deterministic boundaries where possible and representative latency/resource tests.
A production promotion record should name the repository, requested ref, resolved commit, client and framework versions, declared paths, total bytes, per-file hashes, offline and empty-cache results, runtime test identity, evaluation result and approval owner. Keep it beside the deployment definition rather than inside an ephemeral build log.
The lab can now remove its isolated fixture. Cleanup is allowed only when the exact path and marker content match. The guard prevents a copied command from targeting an unrelated cache tree.
test "$LAB_ROOT" = /tmp/voxfor-hf-cache-146-lab
test -f "$MARKER"
test "$(<"$MARKER")" = voxfor-hf-cache-146-v1
find "$LAB_ROOT" -xdev -depth -delete
test ! -e "$LAB_ROOT"
printf '%s\n' 'CLEANUP path_absent=yes scope=marker-owned-lab-only'
If a candidate revision fails any cache, framework, inference, security, quality or capacity check, leave the active deployment on its previously accepted commit and cache. Stop candidate promotion, preserve its receipt and failure evidence for review, remove only the rejected marker-owned candidate path, and rebuild from a newly declared revision or file contract. An already deleted upstream repository is not recoverable from a commit hash alone, so retain an approved internal copy when availability policy requires it.
Branches are designed to move, and a repository owner can also move or recreate a tag. Resolve the selected ref to a full commit during release admission, record both values, and deploy the commit rather than re-resolving the ref at startup.
HF_HUB_OFFLINE=1 prove the correct model is cached?Offline mode alone cannot prove identity. It prevents Hub HTTP calls but does not decide which commit your application intended or whether every required file has the expected bytes. Bind the exact commit, allowlisted paths, byte counts and hashes in an admission receipt.
Only files required by the pinned runtime and workload should enter the release contract. Multiple frameworks, quantizations and exports can coexist in one repository. Use a reviewed allowlist and dry run, then exercise actual framework loading so an omitted dependency fails before promotion.
Not automatically. A local cache accelerates and isolates one deployment, while an internal registry can add retention, access control, provenance review and distribution across environments. Whichever store is used, preserve upstream repository, full commit and per-file integrity evidence.
trust_remote_code=True?A pin prevents surprise changes after review, but it does not prove the code is benign. Inspect the exact revision, minimize privileges and secrets, isolate execution and use native supported implementations when possible. Security policy may require an internal reviewed copy.
Rebuild the manifest and repeat offline resolution, framework loading, tokenizer/processor construction, representative inference, security review, resource capacity, latency and application-quality acceptance. A new commit is a new release even when the repository ID and model card title remain unchanged.