{"record":{"id":"d7306d7fab29ddae","repo":"Comfy-Org/ComfyUI","slug":"node-to-node-id-says-it-needs-input-to-input","errorCode":null,"errorMessage":"Node {to_node_id} says it needs input {to_input}, but there is no input to that node at all","messagePattern":"Node (.+?) says it needs input (.+?), but there is no input to that node at all","errorType":"exception","errorClass":"NodeInputError","httpStatus":null,"severity":"error","filePath":"comfy_execution/graph.py","lineNumber":123,"sourceCode":"\nclass TopologicalSort:\n    def __init__(self, dynprompt):\n        self.dynprompt = dynprompt\n        self.pendingNodes = {}\n        self.blockCount = {} # Number of nodes this node is directly blocked by\n        self.blocking = {} # Which nodes are blocked by this node\n        self.externalBlocks = 0\n        self.unblockedEvent = asyncio.Event()\n\n    def get_input_info(self, unique_id, input_name):\n        class_type = self.dynprompt.get_node(unique_id)[\"class_type\"]\n        class_def = nodes.NODE_CLASS_MAPPINGS[class_type]\n        return get_input_info(class_def, input_name)\n\n    def make_input_strong_link(self, to_node_id, to_input):\n        inputs = self.dynprompt.get_node(to_node_id)[\"inputs\"]\n        if to_input not in inputs:\n            raise NodeInputError(f\"Node {to_node_id} says it needs input {to_input}, but there is no input to that node at all\")\n        value = inputs[to_input]\n        if not is_link(value):\n            raise NodeInputError(f\"Node {to_node_id} says it needs input {to_input}, but that value is a constant\")\n        from_node_id, from_socket = value\n        self.add_strong_link(from_node_id, from_socket, to_node_id)\n\n    def add_strong_link(self, from_node_id, from_socket, to_node_id):\n        if not self.is_cached(from_node_id):\n            self.add_node(from_node_id)\n            if to_node_id not in self.blocking[from_node_id]:\n                self.blocking[from_node_id][to_node_id] = {}\n                self.blockCount[to_node_id] += 1\n            self.blocking[from_node_id][to_node_id][from_socket] = True\n\n    def add_node(self, node_unique_id, include_lazy=False, subgraph_nodes=None):\n        node_ids = [node_unique_id]\n        links = []\n","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_execution/graph.py#L105-L141","documentation":"Raised as NodeInputError by TopologicalSort.make_input_strong_link() in comfy_execution/graph.py when execution is told to make a strong dependency on an input that does not exist in the target node's 'inputs' dict at all. Strong links are established when a node's CHECK_REQUIREMENTS or lazy-input resolution declares it depends on an upstream output; the code path is driven from execution.py where make_input_strong_link(unique_id, i) is called with input names reported by the node class itself.","triggerScenarios":"A custom node's CHECK_REQUIREMENTS or input-resolution returns an input name that is not a key of the node's prompt 'inputs' (e.g. reports 'vae' when the workflow instance lacks that key), or the prompt dict for that node was hand-built with missing input keys. The mismatch between declared dependency and actual prompt data triggers this at queue time.","commonSituations":"Custom-node authors renaming an input but not updating every place the name is reported; workflows where an optional input was stripped from the serialized inputs dict; hand-crafted API prompts omitting optional keys that the node then declares as a dependency; or version skew between a node pack and a workflow saved with an older input set.","solutions":["Update the workflow: re-add the node fresh from the menu so its inputs dict contains every declared input, then reconnect links.","If you own the node code, make CHECK_REQUIREMENTS/lazy-input reporting use the same literal names as INPUT_TYPES and validate against the actual inputs present.","For API prompts, include the reported input key (even with a null/empty value) in the node's inputs dict.","Update the custom node pack — the name mismatch may be a known bug fixed upstream."],"exampleFix":"# before (custom node reports a dependency its instances don't have)\nclass MyNode:\n    @classmethod\n    def CHECK_REQUIREMENTS(cls, inputs, outputs):\n        return [ChangeNodeRequirements('vae')]  # but 'vae' missing from prompt inputs\n\n# after: only require inputs that exist, and keep names in sync\n    @classmethod\n    def CHECK_REQUIREMENTS(cls, inputs, outputs):\n        return [] if 'vae' not in inputs else [ChangeNodeRequirements('vae')]","handlingStrategy":"validation","validationCode":"# before triggering strong-link logic, confirm the input key exists\nnode_inputs = prompt[to_node_id]['inputs']\nassert to_input in node_inputs, f'{to_node_id} lacks input {to_input!r}'","typeGuard":null,"tryCatchPattern":"from comfy_execution.graph import NodeInputError\ntry:\n    execution_list.make_input_strong_link(nid, name)\nexcept NodeInputError as e:\n    logging.warning('skipping strong link: %s', e)","preventionTips":["Node authors: keep CHECK_REQUIREMENTS input names identical to INPUT_TYPES keys.","Include optional inputs (even null) in serialized workflows for nodes that declare dependencies on them.","Re-add nodes fresh after renaming inputs in a custom node."],"tags":["execution","graph","custom-nodes","prompt"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}