fix(models): prefetch configs skipped by hf hub downloads on windows

diffusers pipeline downloads build subfolder config.json allow-patterns
with os.path.join, and huggingface_hub>=1.22 matches patterns with
fnmatchcase which does not normalize path separators
(huggingface/huggingface_hub#4435). On windows the resulting backslash
patterns match nothing, so per-component config.json files are never
downloaded and the incomplete snapshot still passes the diffusers
cache-completeness check, failing every subsequent load with
"no file named config.json".

Prefetch component configs with forward-slash patterns before pipeline
load. This covers all model families and also repairs snapshots already
broken by the bug on the next load attempt. No-op on linux, in offline
mode, and for local folder or single-file models.
This commit is contained in:
CalamitousFelicitousness
2026-07-08 12:15:37 +01:00
parent 70c503f58e
commit 56dc1b5a39
+21
View File
@@ -331,6 +331,26 @@ def load_diffuser_initial(diffusers_load_config: dict, op='model'):
return sd_model, checkpoint_info
def hf_prefetch_configs(checkpoint_info: CheckpointInfo, diffusers_load_config: dict, op='model'):
# diffusers pipeline downloads build subfolder config allow-patterns with os.path.join, and huggingface_hub>=1.22
# matches patterns with fnmatchcase which does not normalize separators (huggingface/huggingface_hub#4435),
# so on windows component config.json files are never downloaded and the incomplete snapshot
# still passes the diffusers cache-completeness check so it is never repaired on load
# prefetching configs with forward-slash patterns both avoids and repairs such snapshots
if os.name != 'nt' or shared.opts.offline_mode:
return
repo_id = path_to_repo(checkpoint_info)
if repo_id is None or '/' not in repo_id or os.path.exists(repo_id): # local folder or single-file model
return
try:
t0 = time.time()
hf.snapshot_download(repo_id, cache_dir=shared.opts.diffusers_dir, revision=diffusers_load_config.get('revision', None), allow_patterns=['*/config.json'])
log.debug(f'Load {op}: repo="{repo_id}" prefetch=configs time={time.time()-t0:.2f}')
except Exception as e:
if debug_load:
log.debug(f'Load {op}: repo="{repo_id}" prefetch=configs {e}')
def load_diffuser_force(detected_model_type: str, checkpoint_info: CheckpointInfo, diffusers_load_config: dict, op='model'):
from modules import sdnq # pylint: disable=unused-import
sd_model = None
@@ -912,6 +932,7 @@ def load_diffuser(checkpoint_info: CheckpointInfo | None = None, op='model', rev
if model_type is None:
log.error(f'Load {op}: pipeline={shared.opts.diffusers_pipeline} not detected')
return
hf_prefetch_configs(checkpoint_info, diffusers_load_config, op)
vae_file = None
if model_type.startswith('Stable Diffusion') and (op == 'model' or op == 'refiner'): # preload vae for sd models
vae_file, vae_source = sd_vae.resolve_vae(checkpoint_info.filename)