{"record":{"id":"da1530f48d59a089","repo":"invoke-ai/InvokeAI","slug":"node-ids-must-match-got-node-dict-id-and-node","errorCode":null,"errorMessage":"Node ids must match, got {node_dict_id} and {node.id}","messagePattern":"Node ids must match, got (.+?) and (.+?)","errorType":"validation","errorClass":"NodeIdMismatchError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/shared/graph.py","lineNumber":1804,"sourceCode":"        \"\"\"Deletes an edge from a graph\"\"\"\n\n        try:\n            list.remove(self.edges, edge)\n            self._remove_edge_from_indexes(edge)\n        except ValueError:\n            pass\n\n    def _validate_unique_node_ids(self) -> None:\n        node_ids = [n.id for n in self.nodes.values()]\n        seen = set()\n        duplicate_node_ids = {nid for nid in node_ids if (nid in seen) or seen.add(nid)}\n        if duplicate_node_ids:\n            raise DuplicateNodeIdError(f\"Node ids must be unique, found duplicates {duplicate_node_ids}\")\n\n    def _validate_node_id_mapping(self) -> None:\n        for node_dict_id, node in self.nodes.items():\n            if node_dict_id != node.id:\n                raise NodeIdMismatchError(f\"Node ids must match, got {node_dict_id} and {node.id}\")\n\n    def _validate_edge_nodes_and_fields(self) -> None:\n        for edge in self.edges:\n            source_node = self.nodes.get(edge.source.node_id, None)\n            if source_node is None:\n                raise NodeNotFoundError(f\"Edge source node {edge.source.node_id} does not exist in the graph\")\n\n            destination_node = self.nodes.get(edge.destination.node_id, None)\n            if destination_node is None:\n                raise NodeNotFoundError(f\"Edge destination node {edge.destination.node_id} does not exist in the graph\")\n\n            if edge.source.field not in source_node.get_output_annotation().model_fields:\n                raise NodeFieldNotFoundError(\n                    f\"Edge source field {edge.source.field} does not exist in node {edge.source.node_id}\"\n                )\n\n            if edge.destination.field not in type(destination_node).model_fields:\n                if isinstance(destination_node, CallSavedWorkflowInvocation) and is_call_saved_workflow_dynamic_input(","sourceCodeStart":1786,"sourceCodeEnd":1822,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/shared/graph.py#L1786-L1822","documentation":"NodeIdMismatchError is raised during graph validation when the dictionary key under which a node is stored in GraphValidationNodes does not equal the node's own `id` field. InvokeAI graphs store nodes in a dict keyed by node id, so a key/id divergence means the graph is internally inconsistent. The library throws this to catch graphs built or deserialized incorrectly before execution.","triggerScenarios":"Calling GraphValidationNodes (or a validator that runs _validate_node_id_mapping) when a node was inserted into the nodes dict under a key different from the node object's `id` attribute — e.g. mutating `node.id` after insertion, constructing the dict manually, or deserializing a JSON graph where top-level keys were edited without updating each node's `id`.","commonSituations":"Hand-editing a workflow JSON file (renaming a node key but not the nested \"id\" field, or vice versa); programmatic graph mutation that changes node.id without re-adding the node; copying node objects between graphs while keeping stale ids.","solutions":["Ensure every node's `id` attribute matches the dict key it is stored under; re-add the node (del + set_node) after changing its id","If editing workflow JSON by hand, update both the top-level key and the nested node \"id\" to the same value","Rebuild the graph programmatically instead of mutating node ids in place","Catch NodeIdMismatchError and log the two mismatched ids to identify the offending node"],"exampleFix":"# before\nnode.id = \"new_id\"  # dict still keyed by \"old_id\"\n\n# after\ndel graph.nodes[\"old_id\"]\nnode.id = \"new_id\"\ngraph.nodes[\"new_id\"] = node  # or use graph.set_node(node)","handlingStrategy":"validation","validationCode":"def check_node_id_mapping(graph):\n    for key, node in graph.nodes.items():\n        if key != node.id:\n            raise ValueError(f\"node keyed as {key!r} has id {node.id!r}\")\n    return True\n\ncheck_node_id_mapping(graph)  # before submitting graph","typeGuard":"def has_consistent_id(key: str, node) -> bool:\n    return isinstance(node.id, str) and node.id == key","tryCatchPattern":"from invokeai.app.services.shared.graph import NodeIdMismatchError\ntry:\n    validate_graph(graph)\nexcept NodeIdMismatchError as e:\n    logger.error(\"graph node id mismatch: %s\", e)","preventionTips":["Never mutate node.id after inserting a node; use set_node to re-key it","When editing workflow JSON, keep top-level keys and nested node \"id\" values identical","Run graph validation before persisting or executing any programmatically built graph"],"tags":["graph","validation","invokeai","node-id"],"backgroundTag":"graph-node-id-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}