calesthio/OpenMontage · error · ComfyUIError
Node {node_id!r} not found in workflow. Available: {list(w.k
Error message
Node {node_id!r} not found in workflow. Available: {list(w.keys())} What it means
ComfyUIError raised by the static patch_workflow helper when a patch references a node_id that is not a key in the workflow dict. patch_workflow deep-copies the graph and writes values into w[node_id]['inputs'][key]; an unknown id means the patch targets nothing. The message lists the workflow's actual node ids so the correct one can be chosen immediately.
Source
Thrown at tools/_comfyui/client.py:496
# Workflow helpers
# ------------------------------------------------------------------
@staticmethod
def load_workflow(path: Path) -> dict:
"""Load a workflow JSON template from disk."""
with open(path) as f:
return json.load(f)
@staticmethod
def patch_workflow(workflow: dict, patches: dict[str, dict[str, Any]]) -> dict:
"""Deep-copy *workflow* and apply *patches*.
*patches* maps ``node_id`` → ``{input_name: value, ...}``.
"""
w = copy.deepcopy(workflow)
for node_id, values in patches.items():
if node_id not in w:
raise ComfyUIError(
f"Node {node_id!r} not found in workflow. "
f"Available: {list(w.keys())}"
)
for key, val in values.items():
w[node_id]["inputs"][key] = val
return w
@staticmethod
def random_seed() -> int:
"""Return a random seed suitable for ComfyUI noise nodes."""
return random.randint(0, 2**32 - 1)
View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Use the 'Available' list in the message to pick the correct node id and rebuild the patch dict
- Inspect the workflow JSON: each top-level key is a node id; find the node whose class_type matches what you want to patch (e.g. KSampler for seed/steps)
- Prefer semantic lookup: find the id programmatically by class_type instead of hardcoding
- Keep patches next to the exact workflow file they belong to so they never drift
Example fix
# before
patches = {"6": {"seed": 42}} # id 6 absent
workflow = ComfyUIClient.patch_workflow(wf, patches)
# after
seed_node = next(nid for nid, n in wf.items() if n["class_type"] == "KSampler")
workflow = ComfyUIClient.patch_workflow(wf, {seed_node: {"seed": 42}}) Defensive patterns
Strategy: type-guard
Validate before calling
def find_nodes_by_class(workflow: dict, class_type: str) -> list[str]:
return [nid for nid, n in workflow.items() if n.get("class_type") == class_type]
seed_nodes = find_nodes_by_class(workflow, "KSampler")
if not seed_nodes:
raise SystemExit("workflow has no KSampler node to patch")
patches = {seed_nodes[0]: {"seed": 42}} Type guard
def patches_are_valid(workflow: dict, patches: dict) -> bool:
return all(nid in workflow for nid in patches) Try / catch
try:
wf = ComfyUIClient.patch_workflow(workflow, patches)
except ComfyUIError as e:
if "not found in workflow" in str(e):
raise SystemExit("patch node id stale — re-derive ids from the current workflow JSON")
raise Prevention
- Derive node ids programmatically by class_type; never hardcode ids from other exports
- Re-validate patches whenever the workflow file is re-exported
- Store patch dicts alongside the exact workflow file they target
When it happens
Trigger: Passing patches keyed by node ids from a different export of the workflow (ids renumbered between UI/API format saves), hand-written patch dicts guessing ids, or ids copied from a tutorial workflow that differs from yours.
Common situations: Workflow re-exported after edits and node ids shifted ('3' became '10'); using a community workflow where the README's patch examples reference its author's ids; string vs int id confusion (patch keys must match the workflow's id strings exactly).
Related errors
- No output artifacts on node {output_node}. Available nodes:
- Node errors: {json.dumps(data['node_errors'])}
- Prompt error: {json.dumps(data['error'])}
- No prompt_id in response: {data}
- Prompt {prompt_id} did not complete within {timeout}s. The j
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/7132dea2a388ee96.
Report an issue: GitHub.