@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 165460941f
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 2, 18:15 UTC

[BugFix] HFValidationError with cloud storage URIs when HF_HUB_OFFLINE=1 (#39155)

Signed-off-by: Injae Ryou <injaeryou@gmail.com>

Injae Ryou committed May 28, 2026 at 00:53 UTC 165460941f5e82b8ddb344515163b43e537f9c3f
4 files changed +63 -10
tests/engine/test_arg_utils.py
+28
@@ -613,3 +613,31 @@ def test_ir_op_priority():
613 )
614 def test_expand_json_human_readable_numbers(input_json, expected_json):
615 assert _expand_json_human_readable_numbers(input_json) == expected_json
616 +
617 +
618 +@pytest.mark.parametrize(
619 + "uri",
620 + ["s3://bucket/model", "gs://bucket/model", "az://container/model"],
621 +)
622 +def test_cloud_storage_uri_skips_get_model_path(uri, monkeypatch):
623 + """Cloud storage URIs should not be passed to get_model_path()
624 + when HF_HUB_OFFLINE=1, as they are not valid HF repo IDs."""
625 + import huggingface_hub
626 +
627 + monkeypatch.setattr(huggingface_hub.constants, "HF_HUB_OFFLINE", True)
628 +
629 + args = EngineArgs(model=uri)
630 + # model should remain the original cloud URI, not raise
631 + assert args.model == uri
632 +
633 +
634 +def test_cloud_storage_tokenizer_skips_get_model_path(monkeypatch):
635 + """Cloud storage tokenizer URI should not be passed to
636 + get_model_path() when HF_HUB_OFFLINE=1."""
637 + import huggingface_hub
638 +
639 + monkeypatch.setattr(huggingface_hub.constants, "HF_HUB_OFFLINE", True)
640 +
641 + args = EngineArgs(model="s3://bucket/model", tokenizer="s3://bucket/tokenizer")
642 + assert args.model == "s3://bucket/model"
643 + assert args.tokenizer == "s3://bucket/tokenizer"
tests/test_config.py
+20
@@ -754,6 +754,26 @@ def test_s3_url_different_models_create_different_directories(mock_pull_files):
754 assert os.path.exists(config2.tokenizer) and os.path.isdir(config2.tokenizer)
755
756
757 +@patch("vllm.transformers_utils.runai_utils.ObjectStorageModel.pull_files")
758 +def test_s3_url_different_model_and_tokenizer(mock_pull_files):
759 + """Test that when model and tokenizer are different cloud URIs,
760 + pull_files receives the correct URI for each."""
761 + mock_pull_files.return_value = None
762 +
763 + model_url = "s3://bucket/model/"
764 + tokenizer_url = "s3://bucket/tokenizer/"
765 +
766 + config = MockConfig(model=model_url, tokenizer=tokenizer_url)
767 + ModelConfig.maybe_pull_model_tokenizer_for_runai(config, model_url, tokenizer_url)
768 +
769 + # pull_files should be called twice: once for model, once for tokenizer
770 + assert mock_pull_files.call_count == 2
771 + # First call: model URI with allow_pattern
772 + assert mock_pull_files.call_args_list[0][0][0] == model_url
773 + # Second call: tokenizer URI with ignore_pattern
774 + assert mock_pull_files.call_args_list[1][0][0] == tokenizer_url
775 +
776 +
777 @pytest.mark.parametrize(
778 ("model_id", "expected_attn_type", "expected_result", "reason"),
779 [
vllm/config/model.py
+1 -1
@@ -888,7 +888,7 @@ class ModelConfig:
888 if is_runai_obj_uri(tokenizer):
889 object_storage_tokenizer = ObjectStorageModel(url=tokenizer)
890 object_storage_tokenizer.pull_files(
891 - model,
891 + tokenizer,
892 ignore_pattern=["*.pt", "*.safetensors", "*.bin", "*.tensors", "*.pth"],
893 )
894 self.tokenizer = object_storage_tokenizer.dir
vllm/engine/arg_utils.py
+14 -9
@@ -747,15 +747,20 @@ class EngineArgs:
747 load_general_plugins()
748 # when use hf offline,replace model and tokenizer id to local model path
749 if huggingface_hub.constants.HF_HUB_OFFLINE:
750 - model_id = self.model
751 - self.model = get_model_path(self.model, self.revision)
752 - if model_id is not self.model:
753 - logger.info(
754 - "HF_HUB_OFFLINE is True, replace model_id [%s] to model_path [%s]",
755 - model_id,
756 - self.model,
757 - )
758 - if self.tokenizer is not None:
750 + # Skip cloud storage URIs (s3://, gs://, az://) — they are not
751 + # HF repo IDs and will be resolved later by
752 + # ModelConfig.maybe_pull_model_tokenizer_for_runai().
753 + if not is_cloud_storage(self.model):
754 + model_id = self.model
755 + self.model = get_model_path(self.model, self.revision)
756 + if model_id is not self.model:
757 + logger.info(
758 + "HF_HUB_OFFLINE is True, replace model_id "
759 + "[%s] to model_path [%s]",
760 + model_id,
761 + self.model,
762 + )
763 + if self.tokenizer is not None and not is_cloud_storage(self.tokenizer):
764 tokenizer_id = self.tokenizer
765 self.tokenizer = get_model_path(self.tokenizer, self.tokenizer_revision)
766 if tokenizer_id is not self.tokenizer: