[v1.26.0] Resolve revisions only once, security hardening, and resource groups for Jobs & Collections
Latest📌 Pin a revision once with resolve_revision
Libraries that download many files one by one (config, weights, tokenizer, processor, ...) had to resolve revision="main" into a commit hash on every call — costing one HTTP request per file and risking two calls landing on two different commits if the repo is updated in between. The new HfApi.resolve_revision resolves the revision once and returns a ResolvedRevision: a str subclass whose value stays the user-facing revision (so error messages keep saying "main") while its .resolved attribute holds the commit hash. Download helpers (hf_hub_download, snapshot_download, get_cached_repo_tree) detect it and use the commit hash directly, guaranteeing every file comes from the same commit. The mapping is also written to the refs/ folder of the cache, so later runs in offline mode transparently fall back to the cached value.
>>> from huggingface_hub import resolve_revision, hf_hub_download
>>> revision = resolve_revision("openai-community/gpt2")
>>> revision
ResolvedRevision(initial=None, resolved='607a30d783dfa663caf39e06633721c8d4cfcd7e')
>>> revision == "main" # readable error messages
True
>>> config = hf_hub_download("openai-community/gpt2", "config.json", revision=revision)
>>> weights = hf_hub_download("openai-community/gpt2", "model.safetensors", revision=revision)📚 Documentation: Manage the cache — Pin a revision (advanced)
🔒 Security hardening for downloads and sandboxes
This release ships two security fixes. First, downloading or uploading to a --local-dir now rejects absolute, drive-relative, root-relative, UNC and ..-traversal filenames on all platforms, interpreting each name under both POSIX and Windows rules (refs CVE-2026-15717). Previously only a Windows-only ..\ check existed, so a malicious repo could write files outside the target directory on Windows clients — and even leak a NetNTLMv2 hash via UNC paths. Legitimate repo filenames never contain such segments, so real downloads are unaffected; note that exotic names like folder/..\..\..\file, previously tolerated on Linux, are now rejected everywhere. Second, Sandbox.create no longer injects your HF token into the job environment to download the sbx-server binary: the bucket is public, so the bootstrap now downloads it anonymously and no HF credential ever lands in the sandbox unless you explicitly opt in with forward_hf_token=True.
- [Download] Reject absolute/UNC/traversal filenames on local_dir & cache paths by @Wauplin in #4540
- [Sandbox] Don't send the HF token to sandbox jobs by @Wauplin in #4583
🗂️ Resource groups for Jobs and Collections
Organization resource groups are now supported across the client. For collections, create_collection accepts an optional resource_group_id, and the new update_collection_resource_group method wraps the dedicated Hub endpoint to assign a collection to a resource group afterwards (passing None removes it). For Jobs, run_job, run_uv_job and create_scheduled_job accept a resource_group_id parameter, mirrored by a --resource-group-id option on the hf jobs run, hf jobs uv run and hf jobs scheduled run commands. Beyond access control within an organization, resource groups are also used for cost attribution and per-group spending limits.
hf jobs run --resource-group-id <group-id> python:3.12 python train.py📚 Documentation: Collections reference, CLI reference
- Support resource groups for collections by @moon-bot-app[bot] in #4575
- feat(jobs): support resource group at Job creation by @moon-bot-app[bot] in #4576
📊 Job names, front and center in the CLI
Job names are now much easier to work with from the terminal. hf jobs ls (and hf jobs scheduled ls) display a dedicated NAME column, and a new --name filter acts as a shortcut for --label name=NAME. The name is also surfaced as a top-level field in hf jobs inspect and in command results, instead of only living inside labels — where it remains for compatibility.
$ hf jobs ls -a --name training-v2
JOB_ID NAME IMAGE/SPACE COMMAND CREATED STATUS RUNTIME
----------- ------------ ----------- ------------ ------------ --------- -------
6a60b190... training-v2 python:3.12 python -c... 2026-07-2... COMPLETED 0s📚 Documentation: Run and manage Jobs
📖 Documentation
- Added Odia (
or) translation of the index, installation and quick-start pages by @indrajeetapache in #4454 - [Docs] Fix Odia (or) docs build, register it in CI, rename tm -> ta by @Wauplin in #4589 — note: Tamil docs URLs move from
/tm/to/ta/(correct ISO 639-1 code) - [Docs] Fix HF_XET_SHARD_CACHE_SIZE_LIMIT default (4GB → 16GB) by @rajatarya in #4593 — docs
- docs(jobs): mention cost attribution/spending-limit in resource_group_id docs by @Pierrci in #4597 — docs
🐛 Bug and typo fixes
- [Download] Reject redacted Xet hashes from tree cache by @seanses in #4595 — fixes xet downloads failing with
Unable to parse string as hex hash valueon gated repos without content access - [Safetensors] Fix truncated header on 100kb boundary by @Wauplin in #4603 — headers of 99994–100000 bytes were silently truncated and failed with
header is not json-encoded string - Reject
token=Falseincreate_inference_endpoint_from_cataloginstead of silently ignoring it by @ckarnell in #4605 - [CLI] Don't crash when stdout can't encode non-ASCII output by @Wauplin in #4610 — fixes
UnicodeEncodeErroron Windows when output is redirected or piped - [Core] Fix tilde expansion in CommitOperationAdd by @Saniyagupte in #4612 — paths like
~/model.binno longer raiseFileNotFoundErroron upload
🏗️ Internal
- [Bot] Update hardware flavor enums and docs by @huggingface-hub-bot[bot] in #4577
- Post-release: bump version to 1.26.0.dev0 by @huggingface-hub-bot[bot] in #4584
- [CI] [Release] Make notify-prs best-effort with a retry by @Wauplin in #4585
- [Release] [CI] Update slack message generation by @Wauplin in #4587
- [Release] [CI] Fix slack message generation follow-ups by @Wauplin in #4588
- [CI] Unpin pytest-rerunfailures to fix cascading fixture setup errors by @Wauplin in #4590