fix(mm): identify sharded Qwen3 encoder folders instead of falling back to unknown - #9561
Open
Pfannkuchensack wants to merge 1 commit into
Open
Conversation
…ck to unknown
The starter-model download `black-forest-labs/FLUX.2-klein-{4B,9B}::text_encoder+tokenizer`
lands the Qwen3 encoder as several `model-0000N-of-0000M.safetensors` shards. The SDNQ
rejection guard in `Qwen3Encoder_Qwen3Encoder_Config` called `mod.load_state_dict()`, which
raises `ValueError("Multiple weight files found for this model")` - not a `NotAMatchError` -
when a folder holds more than one weight file. That aborted this config's probe entirely, so
no candidate matched and the encoder was stored as `unknown`.
Make the SDNQ key check shard-safe: read tensor *names* from the safetensors headers per
shard instead of loading a state dict. That is cheap (no tensor data is materialized), works
for any number of shards, and keeps detecting SDNQ weight+scale pairs even when they are
split across shards. The mirrored fallback in `Qwen3Encoder_SDNQ_Folder_Config` had the same
crash for sharded SDNQ folders and now uses the same helper, with its file scope unchanged.
Verified against a real `FLUX.2-klein-9B::text_encoder+tokenizer` install, which now
identifies as `Qwen3Encoder_Qwen3Encoder_Config` / variant `qwen3_8b`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pfannkuchensack
requested review from
JPPhoto,
blessedcoolant,
dunkeroni and
lstein
as code owners
August 30, 2026 19:44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two users reported that the Qwen3 encoder for FLUX.2 Klein 4B and 9B is registered as an unknown model after downloading it from the starter models list. This is a probing bug, and it is reproducible.
The starter-model source
black-forest-labs/FLUX.2-klein-{4B,9B}::text_encoder+tokenizerlands the encoder on disk as several shards:Qwen3Encoder_Qwen3Encoder_Config._reject_if_sdnq_quantized()callsmod.load_state_dict()as its fallback signal.ModelOnDisk.resolve_weight_file()refuses to pick a file when a folder holds more than one weight file and raises a plainValueError— not aNotAMatchError:Because that is not a
NotAMatchError, it aborts this config's probe instead of being recorded as a non-match, no other candidate matches the folder, and identification falls through toUnknown_Config. Both the 4B and the 9B encoder are multi-shard, so both are affected.This was introduced together with the SDNQ support in #9228 — before that, this config never touched the state dict.
Fix
The SDNQ fallback only needs tensor names, so read them from the safetensors headers per shard rather than loading a state dict:
_files_look_sdnq_quantized()helper — iterates the model's safetensors files, collects keys viasafe_open(...).keys(), and looks for SDNQweight+scalepairs across the union of all shards. No tensor data is materialized, so this is cheap even for a 16 GB encoder, and it works for any number of shards._has_sdnq_keys()now delegates to a shared key predicate so the state-dict and file-based paths cannot drift apart.Qwen3Encoder_SDNQ_Folder_Config's mirrored fallback had the identical crash for sharded SDNQ folders and now uses the same helper. Its file scope is deliberately unchanged (root-level*.safetensorsonly), so this is not a widening of SDNQ detection.Verification
Against a real
black-forest-labs/FLUX.2-klein-9B::text_encoder+tokenizerinstall:Before:
After:
Tests
New
TestShardedQwen3EncoderFolderintests/backend/model_manager/configs/test_qwen3_encoder_config.py:text_encoder/folder (plus a siblingtokenizer/folder, matching the real download layout) identifies as a Qwen3 encoder with the correct variant — this fails onmainwith theValueErrorabove.weightandscaletensors deliberately placed in different shards to prove the union-of-headers check works.tests/backend/model_manager/configs/test_qwen3_encoder_config.pyandtest_qwen3_encoder_sdnq_folder_identification.pypass (24 tests), ruff clean.Related
Two other folder-based configs call
mod.load_state_dict()without an explicit path and would hit the sameValueErroron sharded folders —IPAdapter_InvokeAI_Config_BaseandT5Encoder_BnBLLMint8_Config. Left untouched here to keep this PR scoped to the reported regression.🤖 Generated with Claude Code