Skip to content

ModelPatchLoader: migrate legacy quant metadata before quant detection - #16221

Open
berryber09 wants to merge 1 commit into
Comfy-Org:masterfrom
berryber09:fix/model-patch-loader-legacy-quant-migration
Open

ModelPatchLoader: migrate legacy quant metadata before quant detection#16221
berryber09 wants to merge 1 commit into
Comfy-Org:masterfrom
berryber09:fix/model-patch-loader-legacy-quant-migration

Conversation

@berryber09

Copy link
Copy Markdown

What breaks: `ModelPatchLoader.load_model_patch()` calls `comfy.utils.detect_layer_quantization(sd, "")` directly on the raw `load_torch_file()` output, which only recognizes the native per-tensor `.comfy_quant` marker — it never calls `comfy.utils.convert_old_quants(sd, model_prefix, metadata)` first, unlike every UNET/checkpoint loading path in `comfy/sd.py` (5 call sites). So a legacy/reference-format quantized model patch (metadata carrying `_quantization_metadata` + per-tensor `weight_codebook`/`weight_s_channel`/`weight_s_rel` siblings instead of the native marker) is never detected as quantized: the loader builds a plain full-precision model and `load_state_dict()` fails with "Unexpected key(s)" for every quant-suffix tensor plus K-dimension shape mismatches (the packed W4A8 weight tensor is legitimately half the K-dim of the unpacked model).

Replay proof / before-after: reproduced against a real `asym_w4a8_int8`/ConvRot-256 quantized MiniMax H3 Fun ControlNet Union checkpoint. Before the fix: `detect_layer_quantization` returns `None`, `MiniMaxH3FunControl` is built at full precision, and `load_state_dict()` raises immediately. After inserting `sd, metadata = comfy.utils.convert_old_quants(sd, model_prefix="", metadata=metadata)` right after the `load_torch_file()` call (same placement `comfy/sd.py` already uses everywhere): `detect_layer_quantization` returns `{"mixed_ops": True}`, and the full `MiniMaxH3FunControl` construction + `load_state_dict()` succeeds in under half a second with all control_blocks present. The fix is unconditional and format-agnostic (`convert_old_quants` no-ops when there's nothing to migrate), so it changes nothing for currently-working `ModelPatchLoader` inputs — it only unblocks the previously-unloadable legacy-quant case.

load_model_patch() calls comfy.utils.detect_layer_quantization(sd, "") directly on the
raw loaded state dict, which only recognizes the native per-tensor `.comfy_quant`
marker. A legacy/reference-format quantized checkpoint (metadata carrying
`_quantization_metadata`, per-tensor `weight_codebook`/`weight_s_channel`/
`weight_s_rel` siblings instead of the native marker) is therefore never detected as
quantized, so the loader builds a plain full-precision model and load_state_dict()
fails with "Unexpected key(s)" for every quant-suffix tensor plus K-dimension shape
mismatches (the packed W4A8 weight tensor is legitimately half the K-dim of the
unpacked model).

comfy/sd.py's own UNET/checkpoint loading paths already call
comfy.utils.convert_old_quants(sd, model_prefix, metadata) right after load, at five
separate call sites, specifically to promote this legacy format into native
`.comfy_quant` markers before any detection runs. nodes_model_patch.py's
ModelPatchLoader is the one loader in the codebase that loads a state dict via
load_torch_file() and skips this step, so any legacy-format quantized model patch
(e.g. a W4A8 MiniMax H3 Fun ControlNet Union checkpoint) is unloadable through it,
regardless of which of the loader's format branches it would otherwise match.

Reproduced against a real asym_w4a8_int8/ConvRot-256 quantized MiniMax H3 Fun
ControlNet Union checkpoint (in_dim halved from 5376 to 2688 by 4-bit packing, plus
the codebook/scale sibling tensors): load_model_patch() raises before construction.
Inserting `sd, metadata = comfy.utils.convert_old_quants(sd, model_prefix="",
metadata=metadata)` right after the load_torch_file() call — matching the placement
already used throughout comfy/sd.py — was replayed by hand against the same
checkpoint: detect_layer_quantization() now returns {"mixed_ops": True}, and the full
MiniMaxH3FunControl construction + load_state_dict() succeeds in under half a second
with all control_blocks present.

The fix is unconditional and format-agnostic (convert_old_quants no-ops when there is
nothing to migrate), so it does not change behavior for any currently-working
ModelPatchLoader input — only unblocks the previously-unloadable legacy-quant case.
@github-actions

Copy link
Copy Markdown
Contributor

🎉 Thank you for your contribution, we really appreciate it! 🎉

Like many open source projects, we require contributors to sign our Contributor License Agreement (CLA). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:

  • Confirm that you own your contribution.
  • Keep the right to reuse your own code.
  • Grant us a copyright license to include and share it within our projects.

CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.

To sign, please post a new comment on this PR with exactly the following text:


I have read and agree to the Contributor License Agreement


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 519fcc34-5519-405f-a07c-e0dae64d9365

📥 Commits

Reviewing files that changed from the base of the PR and between a7b1d39 and 4bdeda2.

📒 Files selected for processing (1)
  • comfy_extras/nodes_model_patch.py

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Socket Security: Project Report
⚠️ CI failures not shown inline (2)

GitHub Actions: CLA Assistant / 0_cla-assistant.txt: ModelPatchLoader: migrate legacy quant metadata before quant detection

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   lock-pullrequest-aftermerge: false
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   suggest-recheck: true
 env:
   GITHUB_***REDACTED_SECRET_ASSIGNMENT***
   PERSONAL_ACCESS_***REDACTED_SECRET_ASSIGNMENT***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2150) [DEP0040] DeprecationWar...

GitHub Actions: CLA Assistant / cla-assistant: ModelPatchLoader: migrate legacy quant metadata before quant detection

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   lock-pullrequest-aftermerge: false
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   suggest-recheck: true
 env:
   GITHUB_***REDACTED_SECRET_ASSIGNMENT***
   PERSONAL_ACCESS_***REDACTED_SECRET_ASSIGNMENT***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2150) [DEP0040] DeprecationWar...
🧰 Additional context used
📓 Path-based instructions (3)
Community-contributed extra nodes.

⚙️ CodeRabbit configuration file

Files:

  • comfy_extras/nodes_model_patch.py
IMPORTANT: Only comment on issues directly introduced by this PR's code changes.

⚙️ CodeRabbit configuration file

Files:

  • comfy_extras/nodes_model_patch.py
Documentation and README edits should be concise, factual, and tied to the changed behavior.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • comfy_extras/nodes_model_patch.py
🔇 Additional comments (1)
comfy_extras/nodes_model_patch.py (1)

246-246: LGTM!


📝 Walkthrough

Walkthrough

load_model_patch now calls comfy.utils.convert_old_quants after loading the patch state dictionary and metadata. The conversion runs before weight dtype detection and model construction.

Merge Risk: ⚪ Minimal · up to 4bded

Model patch loading now migrates legacy quantization metadata before model construction, enabling legacy quantized patches to load through the existing quantized path without introducing an identified merge-blocking risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: migrating legacy quantization metadata before quantization detection in ModelPatchLoader.
Description check ✅ Passed The description is directly related to the changeset. It explains the legacy quantization detection failure, the applied fix, and the expected behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant