From 21483d2bdf19c4679a679d077fe331ef09402dfc Mon Sep 17 00:00:00 2001 From: sergioperezcheco Date: Sat, 18 Jul 2026 21:55:10 +0800 Subject: [PATCH] fix(pipelines): use forward slash in per-component config.json download allow patterns DiffusionPipeline.download() built the allow pattern for each model folder's config.json with os.path.join(folder, 'config.json'), which uses a backslash on Windows. Hub repo paths always use forward slashes, and since huggingface_hub 1.22.0 patterns are matched case-sensitively with fnmatch.fnmatchcase (no separator normalization), so the backslash patterns matched nothing on Windows and every component config.json was silently skipped. Build the pattern with a literal forward slash, which matches every other allow_patterns entry in this function. Fixes #14142 Signed-off-by: Sergio Perez --- src/diffusers/pipelines/pipeline_utils.py | 5 ++++- tests/pipelines/test_pipelines.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index d737b44129ea..7147be15af99 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -1784,7 +1784,10 @@ def download(cls, pretrained_model_name, **kwargs) -> str | os.PathLike: # add custom pipeline file allow_patterns += [f"{custom_pipeline}.py"] if f"{custom_pipeline}.py" in filenames else [] # also allow downloading config.json files with the model - allow_patterns += [os.path.join(k, "config.json") for k in model_folder_names] + # Hub repo paths always use forward slashes, so build the pattern + # with "/" instead of os.path.join (which uses "\" on Windows and + # fails to match repo paths with fnmatch.fnmatchcase). + allow_patterns += [f"{k}/config.json" for k in model_folder_names] allow_patterns += [ SCHEDULER_CONFIG_NAME, CONFIG_NAME, diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 8aa874e7aa6d..a85fa822abe9 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -535,6 +535,27 @@ def test_local_files_only_uses_same_snapshot_download_patterns(self): assert set(offline_kwargs["allow_patterns"]) == set(online_kwargs["allow_patterns"]) assert set(offline_kwargs["ignore_patterns"]) == set(online_kwargs["ignore_patterns"]) + def test_download_allow_patterns_use_forward_slash_for_component_configs(self): + # Hub repo paths always use forward slashes, so per-component config.json allow patterns + # must be built with "/" rather than os.path.join (which yields "\" on Windows and then + # fails to match repo paths once huggingface_hub matches patterns case-sensitively). + # See https://github.com/huggingface/diffusers/issues/14142 + with tempfile.TemporaryDirectory() as tmpdirname: + with mock.patch( + "diffusers.pipelines.pipeline_utils.snapshot_download", side_effect=snapshot_download + ) as mock_snapshot_download: + DiffusionPipeline.download( + "hf-internal-testing/tiny-stable-diffusion-torch", cache_dir=tmpdirname + ) + allow_patterns = mock_snapshot_download.call_args.kwargs["allow_patterns"] + + component_config_patterns = [p for p in allow_patterns if p.endswith("/config.json")] + # tiny-stable-diffusion-torch has unet, vae and text_encoder model folders, so there + # must be at least one component config pattern and every one must use "/". + assert len(component_config_patterns) > 0 + for pattern in component_config_patterns: + assert "\\" not in pattern, f"component config pattern {pattern!r} must use forward slash" + def test_local_files_only_raises_for_snapshot_with_missing_weights(self): # An interrupted download leaves a cached snapshot without some weights; loading it offline must # surface `huggingface_hub`'s incomplete-snapshot error instead of failing later at model load time.