Resolve revision to commit_hash once per model load, via huggingface_hub's `resolve_revision` (#49990)
Signed-off-by: Wauplin <lucainp@gmail.com> Signed-off-by: Lucain <lucainp@gmail.com> Signed-off-by: Lucain Pouget <lucain@huggingface.co> Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: OpenAI Codex <codex@openai.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>
Lucain committed
Aug 5, 2026 at 15:49 UTC
397094da1768c7a6f29dfa4f70079d793ac747df
9 files changed
+84
-6
requirements/common.txt
+1
@@ -8,6 +8,7 @@ tqdm
8
blake3
9
py-cpuinfo
10
transformers >= 5.5.3
11
+huggingface_hub >= 1.26.0
12
tokenizers >= 0.21.1 # Required for fast incremental detokenization.
13
safetensors >= 0.6.2 # MXFP4/MXFP6 dtype support (F8_E8M0, F4) added in 0.6.0: https://github.com/huggingface/safetensors/pull/611
14
protobuf >= 5.29.6, !=6.30.*, !=6.31.*, !=6.32.*, !=6.33.0.*, !=6.33.1.*, !=6.33.2.*, !=6.33.3.*, !=6.33.4.* # Required by LlamaTokenizer, gRPC. CVE-2026-0994
requirements/test/cpu.txt
+2
-1
@@ -341,8 +341,9 @@ httpx==0.27.2
341
# schemathesis
342
httpx-sse==0.4.3
343
# via mcp
344
-huggingface-hub==1.22.0
344
+huggingface-hub==1.26.0
345
# via
346
+ # -r requirements/test/../common.txt
347
# accelerate
348
# datasets
349
# evaluate
requirements/test/cuda.txt
+3
-1
@@ -360,8 +360,10 @@ httpx==0.27.2
360
# schemathesis
361
httpx-sse==0.4.3
362
# via mcp
363
-huggingface-hub==1.22.0
363
+huggingface-hub==1.26.0
364
# via
365
+ # -c requirements/common.txt
366
+ # -r requirements/test/../common.txt
367
# accelerate
368
# datasets
369
# evaluate
requirements/test/rocm.txt
+3
-1
@@ -351,8 +351,10 @@ httpx==0.27.2
351
# schemathesis
352
httpx-sse==0.4.3
353
# via mcp
354
-huggingface-hub==1.22.0
354
+huggingface-hub==1.26.0
355
# via
356
+ # -c requirements/common.txt
357
+ # -r requirements/test/../common.txt
358
# accelerate
359
# datasets
360
# evaluate
requirements/test/xpu.txt
+3
-1
@@ -224,8 +224,10 @@ httpx==0.28.1
224
# schemathesis
225
httpx-sse==0.4.3
226
# via mcp
227
-huggingface-hub==1.22.0
227
+huggingface-hub==1.26.0
228
# via
229
+ # -c requirements/common.txt
230
+ # -r requirements/test/../common.txt
231
# accelerate
232
# datasets
233
# evaluate
vllm/config/model.py
+27
@@ -47,6 +47,7 @@ from vllm.transformers_utils.model_arch_config_convertor import (
47
MODEL_ARCH_CONFIG_CONVERTORS,
48
ModelArchConfigConvertorBase,
49
)
50
+from vllm.transformers_utils.repo_utils import resolve_revision
51
from vllm.transformers_utils.runai_utils import ObjectStorageModel, is_runai_obj_uri
52
from vllm.transformers_utils.utils import maybe_model_redirect
53
from vllm.utils.import_utils import LazyLoader
@@ -529,6 +530,7 @@ class ModelConfig:
530
self.served_model_name = get_served_model_name(
531
self.model, self.served_model_name
532
)
533
+ requested_revision = self.revision
534
self.model = maybe_model_redirect(self.model)
535
# The tokenizer is consistent with the model by default.
536
if self.tokenizer is None:
@@ -558,6 +560,31 @@ class ModelConfig:
560
561
self.maybe_pull_model_tokenizer_for_runai(self.model, self.tokenizer)
562
563
+ # If loading model/tokenizer from HF Hub, resolve the revision once
564
+ # to prevent resolving it multiple times downstream.
565
+ can_resolve_model_revision = (
566
+ self.hf_config_path is None or self.hf_config_path == self.model
567
+ )
568
+ if can_resolve_model_revision:
569
+ self.revision = resolve_revision(
570
+ self.model,
571
+ self.revision,
572
+ self.hf_token,
573
+ )
574
+
575
+ if (
576
+ can_resolve_model_revision
577
+ and self.tokenizer == self.model
578
+ and self.tokenizer_revision == requested_revision
579
+ ):
580
+ self.tokenizer_revision = self.revision
581
+ else:
582
+ self.tokenizer_revision = resolve_revision(
583
+ self.tokenizer,
584
+ self.tokenizer_revision,
585
+ self.hf_token,
586
+ )
587
+
588
if self.override_attention_dtype is not None and not current_platform.is_rocm():
589
warnings.warn(
590
"override-attention-dtype is set but not using ROCm platform",
vllm/model_executor/models/ultravox.py
+4
-2
@@ -544,6 +544,8 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
544
[self.config.audio_token_index],
545
)
546
547
+ # The towers live in their own Hub repos, so the revision of the
548
+ # Ultravox repo does not apply to them.
549
self.secondary_weights = []
550
if config.audio_model_id is not None:
551
# this prefix is not for initialization, but for loading weights
@@ -551,7 +553,7 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
553
self.secondary_weights.append(
554
DefaultModelLoader.Source(
555
model_or_path=config.audio_model_id,
554
- revision=vllm_config.model_config.revision,
556
+ revision=None,
557
prefix="audio_tower.",
558
)
559
)
@@ -561,7 +563,7 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
563
self.secondary_weights.append(
564
DefaultModelLoader.Source(
565
model_or_path=config.text_model_id,
564
- revision=vllm_config.model_config.revision,
566
+ revision=None,
567
prefix="language_model.",
568
)
569
)
vllm/transformers_utils/repo_utils.py
+38
@@ -49,6 +49,44 @@ def hf_fs() -> "huggingface_hub.HfFileSystem":
49
)
50
51
52
+def resolve_revision(
53
+ repo_id: str,
54
+ revision: str | None = None,
55
+ token: str | bool | None = None,
56
+) -> str | None:
57
+ """Best-effort attempt to resolve a Hub revision to a commit hash.
58
+
59
+ Resolving the commit hash once prevents repeated HTTP calls downstream and
60
+ avoids races if the branch moves while the model is loading.
61
+
62
+ `HfApi.resolve_revision` returns a `ResolvedRevision`: a `str` equal to the
63
+ requested revision that also carries the commit hash, so downstream error
64
+ messages stay readable and offline loads reuse the cached `refs/` entry.
65
+
66
+ Returns:
67
+ The resolved revision, or `revision` unchanged if it cannot be resolved
68
+ (local path, ModelScope, or any Hub error).
69
+ """
70
+ if Path(repo_id).exists() or envs.VLLM_USE_MODELSCOPE:
71
+ return revision
72
+
73
+ try:
74
+ return hf_api().resolve_revision(
75
+ repo_id,
76
+ revision=revision,
77
+ local_files_only=huggingface_hub.constants.HF_HUB_OFFLINE,
78
+ token=token,
79
+ )
80
+ except Exception:
81
+ logger.debug(
82
+ "Failed to resolve revision for %s; falling back to %s.",
83
+ repo_id,
84
+ revision,
85
+ exc_info=True,
86
+ )
87
+ return revision
88
+
89
+
90
_R = TypeVar("_R")
91
92
vllm/v1/worker/gpu_model_runner.py
+3
@@ -5553,7 +5553,10 @@ class GPUModelRunner(
5553
)
5554
5555
if weights_path is not None:
5556
+ # The revision belongs to the model we are reloading away from,
5557
+ # so it must not be carried over to the new path.
5558
self.model_config.model = weights_path
5559
+ self.model_config.revision = None
5560
weights_iterator = model_loader.get_all_weights(self.model_config, model)
5561
weights_iterator = cast(
5562
Iterable[tuple[str, torch.Tensor]], weights_iterator