Stats
Actions
Tags
From comfyui-node-dev
Use when user encounters errors in ComfyUI custom nodes, asks about debugging, needs to analyze stack traces, troubleshoot execution failures, fix type errors, or diagnose tensor shape mismatches.
How this skill is triggered — by the user, by Claude, or both
Slash command
/comfyui-node-dev:comfyui-debuggingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Category | Symptom | Common Fix |
| Category | Symptom | Common Fix |
|---|---|---|
| Registration | Node not in UI | Check comfy_entrypoint(), get_node_list() |
| Schema | Invalid definition | Add required fields (node_id, category) |
| Type | Mismatch between nodes | Fix input/output types |
| Execution | Runtime failures | Add validation, error handling |
| Cache/Lazy | Wrong caching behavior | Fix fingerprint_inputs(), check_lazy_status() |
Node not appearing in ComfyUI:
| Cause | Solution |
|---|---|
| Missing entry point | Add async def comfy_entrypoint() |
| Node not in list | Add to get_node_list() return |
| Import errors | Check console for import failures |
| Duplicate node_id | Use unique node_id |
# ✅ Correct pattern
async def comfy_entrypoint() -> MyExtension: # Must be async
return MyExtension()
class MyExtension(ComfyExtension):
async def get_node_list(self) -> list[type[io.ComfyNode]]:
return [MyNode] # Node must be here
| Error | Cause | Fix |
|---|---|---|
| Missing 'node_id' | No node_id | Add node_id="UniqueID" |
| Invalid category | Wrong format | Use category/subcategory |
| Output count mismatch | Wrong return count | Match outputs list length |
# ✅ Correct schema
@classmethod
def define_schema(cls):
return io.Schema(
node_id="MyNode", # Required
category="utils/debug", # Use / separator
inputs=[io.String.Input("text")],
outputs=[io.String.Output()],
)
@classmethod
def execute(cls, text): # Must match input name "text"
return io.NodeOutput(text) # One output matches schema
Standard tensor formats:
# IMAGE: [Batch, Height, Width, Channels]
image.shape = (1, 512, 512, 3)
# MASK: [Batch, Height, Width]
mask.shape = (1, 512, 512)
# LATENT: Dictionary with 'samples' key
latent = {"samples": torch.randn(1, 4, 64, 64)} # [B, C, H, W]
Common mistakes:
# ❌ Wrong: returning [B,C,H,W] instead of [B,H,W,C]
result = image.permute(0, 3, 1, 2)
# ✅ Correct: maintain [B,H,W,C]
result = process(image) # Keep original format
@classmethod
def execute(cls, image, strength) -> io.NodeOutput:
# Validate inputs
if not isinstance(image, torch.Tensor):
raise TypeError(f"Expected tensor, got {type(image)}")
if len(image.shape) != 4:
raise ValueError(f"Expected 4D tensor, got {len(image.shape)}D")
try:
result = process(image, strength)
except Exception as e:
print(f"[ERROR] Processing failed: {e}")
raise
return io.NodeOutput(result)
# Early validation with validate_inputs()
@classmethod
def validate_inputs(cls, image, strength) -> bool | str:
if strength < 0 or strength > 10:
return f"Strength must be 0-10, got {strength}"
return True
Fingerprint issues:
# ❌ Unstable fingerprint (always re-executes)
@classmethod
def fingerprint_inputs(cls, seed, **kwargs):
return time.time()
# ✅ Stable fingerprint
@classmethod
def fingerprint_inputs(cls, seed, **kwargs):
return seed # Only re-executes when seed changes
Lazy evaluation issues:
# ✅ Correct lazy pattern
def check_lazy_status(self, condition, on_true=None, on_false=None):
if condition and on_true is None:
return ["on_true"]
if not condition and on_false is None:
return ["on_false"]
return []
Traceback (most recent call last):
File "comfy/execution.py", line 154, in execute_node
output = node.execute(**inputs) ← Entry point
File "custom_nodes/my_extension.py", line 42, in execute
result = self.process(image) ← Your code
File "custom_nodes/my_extension.py", line 56, in process
return image * self.strength ← Error location
TypeError: unsupported operand type(s) for *: 'dict' and 'float'
Analysis steps:
custom_nodes/)# Check tensor shape and type
print(f"Shape: {tensor.shape}, Type: {tensor.dtype}")
# Check dictionary structure
print(f"Keys: {list(dict_obj.keys())}")
# Validate input types
print(f"Types: {[(k, type(v)) for k, v in inputs.items()]}")
| Error Message | Root Cause | Quick Fix |
|---|---|---|
Node not found: MyNode | Not registered | Add to get_node_list() |
Missing field 'node_id' | Schema incomplete | Add node_id |
Cannot connect Image to String | Type mismatch | Fix types |
Output count mismatch | Wrong return count | Match outputs |
KeyError: 'samples' | Latent dict wrong | Return {"samples": tensor} |
CUDA out of memory | GPU full | Reduce batch/image size |
Shape mismatch [1,512,512,3] vs [1,3,512,512] | Wrong format | Use [B,H,W,C] |
print(f"[DEBUG] Image: shape={image.shape}, dtype={image.dtype}")
assert len(image.shape) == 4, f"Expected 4D, got {len(image.shape)}D"
assert image.shape[-1] in [1, 3, 4], f"Invalid channels: {image.shape[-1]}"
try:
result = process(image)
except Exception as e:
print(f"[ERROR] Context: shape={image.shape}, type={type(image)}")
raise
Creates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.
npx claudepluginhub juyeongyi/jylee_claude_marketplace --plugin comfyui-node-dev