{"record":{"id":"7bbaed269e7fb1ca","repo":"invoke-ai/InvokeAI","slug":"destination-node-edge-destination-node-id-has-al-7bbaed","errorCode":null,"errorMessage":"Destination node {edge.destination.node_id} has already been prepared or executed and cannot have a source edge deleted","messagePattern":"Destination node (.+?) has already been prepared or executed and cannot have a source edge deleted","errorType":"exception","errorClass":"NodeAlreadyExecutedError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/shared/graph.py","lineNumber":2874,"sourceCode":"        self.graph.update_node(node_id, new_node)\n\n    def delete_node(self, node_id: str) -> None:\n        if not self._is_node_updatable(node_id):\n            raise NodeAlreadyExecutedError(\n                f\"Node {node_id} has already been prepared or executed and cannot be deleted\"\n            )\n        self.graph.delete_node(node_id)\n\n    def add_edge(self, edge: Edge) -> None:\n        if not self._is_node_updatable(edge.destination.node_id):\n            raise NodeAlreadyExecutedError(\n                f\"Destination node {edge.destination.node_id} has already been prepared or executed and cannot be linked to\"\n            )\n        self.graph.add_edge(edge)\n\n    def delete_edge(self, edge: Edge) -> None:\n        if not self._is_node_updatable(edge.destination.node_id):\n            raise NodeAlreadyExecutedError(\n                f\"Destination node {edge.destination.node_id} has already been prepared or executed and cannot have a source edge deleted\"\n            )\n        self.graph.delete_edge(edge)\n","sourceCodeStart":2856,"sourceCodeEnd":2878,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/shared/graph.py#L2856-L2878","documentation":"GraphExecution.delete_edge throws NodeAlreadyExecutedError when the edge's destination node has already been prepared or executed. Removing an edge to an executed node would invalidate recorded execution results, so it is blocked. Delete edges only before the graph runs.","triggerScenarios":"Calling GraphExecution.delete_edge(edge) where edge.destination.node_id has already been prepared or executed.","commonSituations":"Live graph editing via the UI/websocket during a run, cleanup code that removes stale edges after execution, or re-running an old queue item's session object.","solutions":["Remove the edge before the graph is queued for execution","Copy the graph, delete the edge on the copy, and enqueue the new graph","Catch NodeAlreadyExecutedError and treat the edge as already-locked","Check _is_node_updatable(edge.destination.node_id) before delete_edge"],"exampleFix":"// before\nexecution.delete_edge(edge)  # raises if destination already executed\n// after\nif execution._is_node_updatable(edge.destination.node_id):\n    execution.delete_edge(edge)","handlingStrategy":"validation","validationCode":"if not execution._is_node_updatable(edge.destination.node_id):\n    return  # edge is locked to an executed node\nexecution.delete_edge(edge)","typeGuard":"def edge_deletable(execution, edge: Edge) -> bool:\n    return execution._is_node_updatable(edge.destination.node_id)","tryCatchPattern":"try:\n    execution.delete_edge(edge)\nexcept NodeAlreadyExecutedError as e:\n    logger.info(\"edge locked: %s\", e)","preventionTips":["Clean up edges before execution starts","Treat executed graphs as read-only","Requeue modified copies instead of editing live sessions"],"tags":["graph","invokeai","state-error","edges"],"backgroundTag":"immutable-state-modification","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}