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

  1. Use the 'Available' list in the message to pick the correct node id and rebuild the patch dict
  2. 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)
  3. Prefer semantic lookup: find the id programmatically by class_type instead of hardcoding
  4. 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

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


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/7132dea2a388ee96. Report an issue: GitHub.