a repo id resolves to pipeline.py, so three live models reported 404

MOSS-Image-SFT, MOSS-Image-NSFW and Kromoss all failed as "Failed to load
image model", with a 404 naming the repository -- which read as the model not
existing on the Hub. All three repositories are public and complete; the 404
was on a file.

They declare _class_name: MOSSImagePipeline, a class that ships in the repo,
so kwargs_for_declared_class passed custom_pipeline=<repo id>. diffusers
resolves a repo id by one convention only: pipeline.py at the root. These
repos call their file pipeline_moss_image.py, so every attempt fetched
<repo>/resolve/main/pipeline.py -- a path that had never existed.

So read the module name instead of assuming it. model_index.json names it: a
component slot holding neither diffusers nor any installed package is naming a
module that travels with the weights ("scheduler": ["pipeline_moss_image",
"MOSSImageScheduler"]). Given that bare name diffusers does the right thing --
load_pipe_from_hub looks for <module>.py among the repo's files and loads it
from the repo. None when the repo does ship pipeline.py, so every community
pipeline keeps the resolution that is already correct for it.

The log line now names repo and module both, since the gap between them is
what a 404 on this path is about.
Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014T3rZozi1Ehk96NG1WesgC
parent cf9bdcba
...@@ -901,8 +901,13 @@ def _load_diffusers_pipeline(model_name: str, global_args, model_config: dict = ...@@ -901,8 +901,13 @@ def _load_diffusers_pipeline(model_name: str, global_args, model_config: dict =
getattr(_cm, "config", None), model_name) getattr(_cm, "config", None), model_name)
if _img_remote: if _img_remote:
_declared = _img_remote.pop("_declared_class", None) _declared = _img_remote.pop("_declared_class", None)
# Name the module as well as the repo: the two differ whenever the
# pipeline file is not the conventional pipeline.py, and that
# difference is what a 404 on this path is about.
_cp = _img_remote['custom_pipeline']
_where = _cp if _cp == model_name else f"{model_name} ({_cp}.py)"
print(f" Custom pipeline from the repository: " print(f" Custom pipeline from the repository: "
f"{_img_remote['custom_pipeline']} (allow-listed)" f"{_where} (allow-listed)"
+ (f" — it declares {_declared}, which is not in diffusers" + (f" — it declares {_declared}, which is not in diffusers"
if _declared else "")) if _declared else ""))
except PermissionError: except PermissionError:
......
...@@ -92,12 +92,13 @@ def kwargs_for(cfg, repo: str, custom_pipeline: Optional[str]) -> dict: ...@@ -92,12 +92,13 @@ def kwargs_for(cfg, repo: str, custom_pipeline: Optional[str]) -> dict:
return {"custom_pipeline": name, "trust_remote_code": True} return {"custom_pipeline": name, "trust_remote_code": True}
def declared_pipeline_class(repo: str) -> Optional[str]: def _model_index(repo: str) -> Optional[dict]:
"""The ``_class_name`` the repo's ``model_index.json`` declares, or None. """The repo's parsed ``model_index.json``, or None.
Read rather than guessed, because the name is the only thing that says a Fetched, not read cache-only: a repo being loaded for the first time has no
repository means to supply its own pipeline: MOSS-Image declares cache yet, and a cache-only answer to "what does this declare" is
``MOSSImagePipeline``, which exists in the repo and nowhere in diffusers. permanently wrong on a freshly-rented pod. The file is a few hundred bytes
and the weights are about to follow.
""" """
import json import json
import os import os
...@@ -108,20 +109,89 @@ def declared_pipeline_class(repo: str) -> Optional[str]: ...@@ -108,20 +109,89 @@ def declared_pipeline_class(repo: str) -> Optional[str]:
return None return None
else: else:
from huggingface_hub import hf_hub_download from huggingface_hub import hf_hub_download
# Fetched, not read cache-only: a repo being loaded for the first
# time has no cache yet, and a cache-only answer to "what class does
# this declare" is permanently wrong on a freshly-rented pod. The
# file is a few hundred bytes and the weights are about to follow.
path = hf_hub_download(repo, "model_index.json") path = hf_hub_download(repo, "model_index.json")
with open(path) as fh: with open(path) as fh:
name = (json.load(fh) or {}).get("_class_name") idx = json.load(fh)
return str(name) if name else None return idx if isinstance(idx, dict) else None
except Exception: except Exception:
# Not a diffusers repo, not reachable, or no index. Either way there is # Not a diffusers repo, not reachable, or no index. Either way there is
# nothing to declare, and the ordinary load must be left alone. # nothing to declare, and the ordinary load must be left alone.
return None return None
def declared_pipeline_class(repo: str) -> Optional[str]:
"""The ``_class_name`` the repo's ``model_index.json`` declares, or None.
Read rather than guessed, because the name is the only thing that says a
repository means to supply its own pipeline: MOSS-Image declares
``MOSSImagePipeline``, which exists in the repo and nowhere in diffusers.
"""
name = (_model_index(repo) or {}).get("_class_name")
return str(name) if name else None
def _is_installed_library(name: str) -> bool:
"""Whether ``name`` is a package here, rather than a file in some repo."""
try:
import importlib.util
return importlib.util.find_spec(name) is not None
except Exception:
# A dotted or malformed candidate, or a package whose import machinery
# objects. Either way it is not a plain module in a model repository.
return True
def _repo_has_root_file(repo: str, name: str) -> bool:
import os
try:
if os.path.isdir(repo):
return os.path.isfile(os.path.join(repo, name))
from huggingface_hub import list_repo_files
return name in set(list_repo_files(repo))
except Exception:
return False
def declared_pipeline_module(repo: str) -> Optional[str]:
"""The module INSIDE ``repo`` that holds its pipeline class, or None.
diffusers resolves a ``custom_pipeline`` given as a repository by one
convention only: the file is called ``pipeline.py``. So passing the repo id
for MOSS-Image and Kromoss, whose file is ``pipeline_moss_image.py``,
fetched ``<repo>/resolve/main/pipeline.py`` and got a 404 -- on a path that
had never existed. That reads as "this model is not on Hugging Face", which
is how three working repositories came to be reported as wrong names.
The real module name is in ``model_index.json``: a component whose library
slot holds neither diffusers nor any installed package is naming a module
that travels with the weights::
"scheduler": ["pipeline_moss_image", "MOSSImageScheduler"]
Given that bare name diffusers does the right thing -- it looks for
``<module>.py`` among the repo's own files and, finding it, loads the module
from the repo -- so return the name rather than the id. None when the repo
follows the ``pipeline.py`` convention after all, or says nothing useful, so
the caller keeps the behaviour that is correct for every community pipeline.
"""
idx = _model_index(repo) or {}
seen = []
for key, value in idx.items():
if key.startswith("_") or not isinstance(value, (list, tuple)):
continue
if not value or not isinstance(value[0], str):
continue
candidate = value[0].strip()
if not candidate or candidate in seen:
continue
seen.append(candidate)
if _is_installed_library(candidate):
continue
if _repo_has_root_file(repo, f"{candidate}.py"):
return candidate
return None
def kwargs_for_declared_class(cfg, repo: str) -> dict: def kwargs_for_declared_class(cfg, repo: str) -> dict:
"""``from_pretrained`` kwargs for a repo whose pipeline class is its own. """``from_pretrained`` kwargs for a repo whose pipeline class is its own.
...@@ -150,5 +220,8 @@ def kwargs_for_declared_class(cfg, repo: str) -> dict: ...@@ -150,5 +220,8 @@ def kwargs_for_declared_class(cfg, repo: str) -> dict:
except Exception: except Exception:
return {} return {}
require(cfg, repo, f"its own pipeline class {cls!r}") require(cfg, repo, f"its own pipeline class {cls!r}")
return {"custom_pipeline": repo, "trust_remote_code": True, # The module the repo keeps it in when it is not the conventional
# ``pipeline.py``; the id otherwise. See :func:`declared_pipeline_module`.
module = declared_pipeline_module(repo)
return {"custom_pipeline": module or repo, "trust_remote_code": True,
"_declared_class": cls} "_declared_class": cls}
...@@ -164,13 +164,95 @@ def test_a_repo_declaring_an_unavailable_class_is_detected(monkeypatch): ...@@ -164,13 +164,95 @@ def test_a_repo_declaring_an_unavailable_class_is_detected(monkeypatch):
from codai.models import remote_code as R from codai.models import remote_code as R
monkeypatch.setattr(R, "declared_pipeline_class", monkeypatch.setattr(R, "declared_pipeline_class",
lambda repo: "MOSSImagePipeline") lambda repo: "MOSSImagePipeline")
monkeypatch.setattr(R, "declared_pipeline_module",
lambda repo: "pipeline_moss_image")
kw = R.kwargs_for_declared_class(_cfg(["openmoss-team/*"]), kw = R.kwargs_for_declared_class(_cfg(["openmoss-team/*"]),
"OpenMOSS-Team/MOSS-Image-SFT") "OpenMOSS-Team/MOSS-Image-SFT")
assert kw["trust_remote_code"] is True assert kw["trust_remote_code"] is True
assert kw["custom_pipeline"] == "OpenMOSS-Team/MOSS-Image-SFT" assert kw["custom_pipeline"] == "pipeline_moss_image"
assert kw["_declared_class"] == "MOSSImagePipeline" assert kw["_declared_class"] == "MOSSImagePipeline"
def test_the_repo_id_is_kept_when_the_file_is_the_conventional_one(monkeypatch):
"""Every community pipeline ships pipeline.py, and for those the id is
exactly what diffusers wants. Only the odd one out gets the module name."""
from codai.models import remote_code as R
monkeypatch.setattr(R, "declared_pipeline_class",
lambda repo: "WhateverPipeline")
monkeypatch.setattr(R, "declared_pipeline_module", lambda repo: None)
kw = R.kwargs_for_declared_class(_cfg(["org/*"]), "org/community-thing")
assert kw["custom_pipeline"] == "org/community-thing"
# ---------------------------------------------------------------------------
# Finding the module the pipeline actually lives in
# ---------------------------------------------------------------------------
MOSS_INDEX = {
"_class_name": "MOSSImagePipeline",
"_diffusers_version": "0.38.0",
"scheduler": ["pipeline_moss_image", "MOSSImageScheduler"],
"text_encoder": ["transformers", "Qwen3_5Model"],
"tokenizer": ["transformers", "Qwen2Tokenizer"],
"transformer": ["pipeline_moss_image", "MOSSImageTransformer"],
"vae": ["diffusers", "AutoencoderKLFlux2"],
}
def _repo_dir(tmp_path, index, files=()):
import json
(tmp_path / "model_index.json").write_text(json.dumps(index))
for name in files:
(tmp_path / name).write_text("# code\n")
return str(tmp_path)
def test_the_module_is_read_from_the_index_not_assumed_to_be_pipeline_py(tmp_path):
"""Kromoss and MOSS-Image as they are published: the class is in
pipeline_moss_image.py, and asking for pipeline.py 404s on a file that
never existed -- which is what made three live repositories look like
wrong model names."""
from codai.models import remote_code as R
repo = _repo_dir(tmp_path, MOSS_INDEX, ["pipeline_moss_image.py"])
assert R.declared_pipeline_module(repo) == "pipeline_moss_image"
def test_an_installed_library_is_never_mistaken_for_a_module_in_the_repo(tmp_path):
"""'transformers' and 'diffusers' sit in the same slot of the index as the
repo's own module; picking one of those would name a file nobody ships."""
from codai.models import remote_code as R
index = dict(MOSS_INDEX)
index.pop("scheduler")
index.pop("transformer")
repo = _repo_dir(tmp_path, index, ["transformers.py", "diffusers.py"])
assert R.declared_pipeline_module(repo) is None
def test_a_named_module_the_repo_does_not_ship_is_not_returned(tmp_path):
"""diffusers only takes the bare name when <module>.py is among the repo's
files; returning one that is missing would swap one 404 for another."""
from codai.models import remote_code as R
repo = _repo_dir(tmp_path, MOSS_INDEX) # index only, no .py
assert R.declared_pipeline_module(repo) is None
def test_an_ordinary_repo_names_no_module(tmp_path):
from codai.models import remote_code as R
repo = _repo_dir(tmp_path, {
"_class_name": "StableDiffusionXLPipeline",
"unet": ["diffusers", "UNet2DConditionModel"],
"text_encoder": ["transformers", "CLIPTextModel"],
})
assert R.declared_pipeline_module(repo) is None
def test_the_class_still_comes_from_the_same_index(tmp_path):
from codai.models import remote_code as R
repo = _repo_dir(tmp_path, MOSS_INDEX, ["pipeline_moss_image.py"])
assert R.declared_pipeline_class(repo) == "MOSSImagePipeline"
assert R.declared_pipeline_class(str(tmp_path / "nope")) is None
def test_such_a_repo_is_refused_by_name_when_not_allow_listed(monkeypatch): def test_such_a_repo_is_refused_by_name_when_not_allow_listed(monkeypatch):
"""The refusal has to name the setting — that is the whole reason the """The refusal has to name the setting — that is the whole reason the
allow-list is spelled out rather than implied.""" allow-list is spelled out rather than implied."""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment