9.9 KiB
Complete Explanation of PR #28 and Additional Fixes
① Proposal Content and What the Problem Was
PR #28 Proposal Content
Title: Fix missing 1 required positional argument: 'cpu_offload'
Problem Description: After the kjai node update, the following error occurred:
TypeError: load_lora() missing 1 required positional argument: 'cpu_offload'
or
TypeError: load_lora_stack() missing 1 required positional argument: 'cpu_offload'
Root Cause
Code Before Fix:
def load_lora(self, model, lora_name: str, lora_strength: float, cpu_offload: str):
# cpu_offload is a required argument (no default value)
Problems:
- Required Parameter:
cpu_offloadwas a required parameter without a default value, causing errors when not provided - ComfyUI Parameter Passing: ComfyUI automatically passes
requiredparameters fromINPUT_TYPES()to methods, but kjai node updates changed how parameters are passed in some call paths - Compatibility Issues: In certain node invocation scenarios (old workflows, dynamic node generation, or kjai node updates), the parameter could be missing
Why It Became a Problem:
- Even though
cpu_offloadis defined asrequiredinINPUT_TYPES(), ComfyUI's node invocation mechanism doesn't always guarantee that all parameters are passed - The kjai node update modified how nodes are invoked, potentially causing parameter omissions in some call paths
- This is a compatibility issue that arose from external node updates
② How We Fixed It (File Names and Code)
Files Modified
nodes/lora/qwenimage.py- 4 locations fixednodes/lora/qwenimage_v2.py- 2 locations fixed
Fix 1: PR #28 Fixes (FUNCTION Methods)
File: nodes/lora/qwenimage.py
Fix Location 1: NunchakuQwenImageLoraLoader.load_lora() method (line 91)
# Before
def load_lora(self, model, lora_name: str, lora_strength: float, cpu_offload: str):
# After
def load_lora(self, model, lora_name: str, lora_strength: float, cpu_offload: str = "disable"):
Fix Location 2: NunchakuQwenImageLoraStack.load_lora_stack() method (line 271)
# Before
def load_lora_stack(self, model, lora_count, cpu_offload, **kwargs):
# After
def load_lora_stack(self, model, lora_count, cpu_offload="disable", **kwargs):
File: nodes/lora/qwenimage_v2.py
Fix Location 3: NunchakuQwenImageLoraStackV2.load_lora_stack() method (line 113)
# Before
def load_lora_stack(self, model, lora_count, cpu_offload, **kwargs):
# After
def load_lora_stack(self, model, lora_count, cpu_offload="disable", **kwargs):
Fix 2: Additional Fixes Applied (IS_CHANGED Methods)
File: nodes/lora/qwenimage.py
Fix Location 4: NunchakuQwenImageLoraLoader.IS_CHANGED() method (line 36)
# Before
@classmethod
def IS_CHANGED(s, model, lora_name, lora_strength, cpu_offload, *args, **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(lora_name.encode())
m.update(str(lora_strength).encode())
m.update(str(model).encode())
m.update(cpu_offload.encode())
return m.digest().hex()
# After
@classmethod
def IS_CHANGED(s, model, lora_name, lora_strength, cpu_offload="disable", *args, **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(lora_name.encode())
m.update(str(lora_strength).encode())
m.update(str(model).encode())
m.update(cpu_offload.encode())
return m.digest().hex()
Fix Location 5: NunchakuQwenImageLoraStack.IS_CHANGED() method (line 195)
# Before
@classmethod
def IS_CHANGED(cls, model, lora_count, cpu_offload, **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(str(model).encode())
m.update(str(lora_count).encode())
m.update(cpu_offload.encode())
# Hash all LoRA parameters
for i in range(1, 11):
m.update(kwargs.get(f"lora_name_{i}", "").encode())
m.update(str(kwargs.get(f"lora_strength_{i}", 0)).encode())
return m.digest().hex()
# After
@classmethod
def IS_CHANGED(cls, model, lora_count, cpu_offload="disable", **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(str(model).encode())
m.update(str(lora_count).encode())
m.update(cpu_offload.encode())
# Hash all LoRA parameters
for i in range(1, 11):
m.update(kwargs.get(f"lora_name_{i}", "").encode())
m.update(str(kwargs.get(f"lora_strength_{i}", 0)).encode())
return m.digest().hex()
File: nodes/lora/qwenimage_v2.py
Fix Location 6: NunchakuQwenImageLoraStackV2.IS_CHANGED() method (line 36)
# Before
@classmethod
def IS_CHANGED(cls, model, lora_count, cpu_offload, **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(str(model).encode())
m.update(str(lora_count).encode())
m.update(cpu_offload.encode())
# Hash all LoRA parameters
for i in range(1, 11):
m.update(kwargs.get(f"lora_name_{i}", "").encode())
m.update(str(kwargs.get(f"lora_strength_{i}", 0)).encode())
return m.digest().hex()
# After
@classmethod
def IS_CHANGED(cls, model, lora_count, cpu_offload="disable", **kwargs):
"""
Detect changes to trigger node re-execution.
Returns a hash of relevant parameters to detect changes.
"""
import hashlib
m = hashlib.sha256()
m.update(str(model).encode())
m.update(str(lora_count).encode())
m.update(cpu_offload.encode())
# Hash all LoRA parameters
for i in range(1, 11):
m.update(kwargs.get(f"lora_name_{i}", "").encode())
m.update(str(kwargs.get(f"lora_strength_{i}", 0)).encode())
return m.digest().hex()
Summary of Fixes
| File | Class | Method | Line | Fix Type |
|---|---|---|---|---|
qwenimage.py |
NunchakuQwenImageLoraLoader |
load_lora() |
91 | PR #28 |
qwenimage.py |
NunchakuQwenImageLoraLoader |
IS_CHANGED() |
36 | Additional |
qwenimage.py |
NunchakuQwenImageLoraStack |
load_lora_stack() |
271 | PR #28 |
qwenimage.py |
NunchakuQwenImageLoraStack |
IS_CHANGED() |
195 | Additional |
qwenimage_v2.py |
NunchakuQwenImageLoraStackV2 |
load_lora_stack() |
113 | PR #28 |
qwenimage_v2.py |
NunchakuQwenImageLoraStackV2 |
IS_CHANGED() |
36 | Additional |
Total: 2 files, 6 locations fixed
③ What It Means
1. Technical Meaning
Effect of Default Arguments:
# Before (required argument)
def load_lora(self, model, lora_name: str, lora_strength: float, cpu_offload: str):
# Error if cpu_offload is not provided
# After (with default value)
def load_lora(self, model, lora_name: str, lora_strength: float, cpu_offload: str = "disable"):
# Uses "disable" if cpu_offload is not provided
Behavior:
- If
cpu_offloadis passed, that value is used - If
cpu_offloadis missing, the default value"disable"is automatically used - This prevents
TypeErrorand ensures the function always receives a valid value
2. Why "disable"?
Looking at the INPUT_TYPES() definition:
"cpu_offload": (
["auto", "enable", "disable"],
{
"default": "disable",
"tooltip": "CPU offload setting. 'auto' enables offload when VRAM is low, 'enable' forces offload, 'disable' disables offload.",
},
),
Reason:
- The UI default value is
"disable" - To maintain consistency between UI defaults and implementation defaults
"disable"means "no CPU offload" (better performance when VRAM is sufficient), which is the recommended default
3. Functional Meaning
Fix for FUNCTION Methods:
- Prevents errors when
cpu_offloadparameter is missing inload_lora()andload_lora_stack() - Ensures compatibility with kjai node updates
Fix for IS_CHANGED Methods:
- ComfyUI calls
IS_CHANGED()to detect changes and determine if node re-execution is needed - If
cpu_offloadis missing inIS_CHANGED()calls, it could causeAttributeErrorwhen calling.encode() - Adding default values prevents errors in change detection as well
4. Compatibility Meaning
Backward Compatibility:
- Existing workflows continue to work without modification
- Maintains compatibility with updated or new nodes
Future-Proofing:
- Prevents similar errors when parameters are missing in various invocation scenarios
- More robust integration with external nodes
5. Design Meaning
Defensive Programming:
- Protects against unexpected external factors (like node updates)
- Provides fallback behavior through default values
Consistency:
- UI defaults match implementation defaults
- User expectations align with actual behavior
6. Practical Meaning
Error Prevention:
- Eliminates
TypeError: missing 1 required positional argumenterrors - More robust operation
User Experience:
- Fewer errors for end users
- More stable operation
Summary
Problem
After the kjai node update, cpu_offload parameter could be missing, causing TypeError.
Solution
Added default value "disable" to both FUNCTION methods (load_lora, load_lora_stack) and IS_CHANGED methods for all three node classes.
Result
- ✅ Error prevention
- ✅ Backward compatibility maintained
- ✅ Consistency with UI defaults
- ✅ More robust implementation
This fix is a defensive programming approach to handle compatibility issues caused by external node updates.