{"record":{"id":"d4250d166da627f5","repo":"invoke-ai/InvokeAI","slug":"node-node-id-has-already-been-prepared-or-execut-d4250d","errorCode":null,"errorMessage":"Node {node_id} has already been prepared or executed and cannot be deleted","messagePattern":"Node (.+?) has already been prepared or executed and cannot be deleted","errorType":"exception","errorClass":"NodeAlreadyExecutedError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/shared/graph.py","lineNumber":2860,"sourceCode":"        return True\n\n    def _is_node_updatable(self, node_id: str) -> bool:\n        # The node is updatable as long as it hasn't been prepared or executed\n        return node_id not in self.source_prepared_mapping\n\n    def add_node(self, node: BaseInvocation) -> None:\n        self.graph.add_node(node)\n\n    def update_node(self, node_id: str, new_node: BaseInvocation) -> 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 updated\"\n            )\n        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":2842,"sourceCodeEnd":2878,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/shared/graph.py#L2842-L2878","documentation":"GraphExecution throws NodeAlreadyExecutedError when deleting a node from a graph that has been prepared or executed. InvokeAI freezes executed graphs so in-flight or completed queue items cannot be mutated. Delete the node before the graph is queued, or work on a fresh copy of the graph.","triggerScenarios":"Calling GraphExecution.delete_node(node_id) after self._is_node_updatable(node_id) returns False, i.e. the node is already in the prepared/executed node list of the running session.","commonSituations":"Dynamic graph editing APIs (node deleted via websocket/API mid-run), a batch workflow that tries to prune nodes after execution started, or reusing a cached GraphExecution object across runs.","solutions":["Delete the node before adding the graph to the queue, not after execution begins","Clone/copy the graph, mutate the copy, and enqueue a new queue item instead of mutating the executed one","Catch NodeAlreadyExecutedError and skip or log when the node is no longer needed","Check _is_node_updatable (or track node state) before calling delete_node"],"exampleFix":"// before\nexecution.delete_node(\"node-1\")  # raises if already run\n// after\nif execution._is_node_updatable(\"node-1\"):\n    execution.delete_node(\"node-1\")\nelse:\n    # mutate a fresh copy and enqueue a new item\n    new_graph = execution._graph.model_copy(deep=True)","handlingStrategy":"validation","validationCode":"if not execution._is_node_updatable(node_id):\n    raise SkipMutation(f\"node {node_id} already executed\")\nexecution.delete_node(node_id)","typeGuard":"def can_mutate(execution, node_id: str) -> bool:\n    return execution._is_node_updatable(node_id)","tryCatchPattern":"try:\n    execution.delete_node(node_id)\nexcept NodeAlreadyExecutedError as e:\n    logger.warning(\"skipped delete on executed graph: %s\", e)","preventionTips":["Mutate graphs only before enqueueing","Work on deep-copied graphs for late edits","Track execution state in your editing UI","Wrap dynamic edits in try/except NodeAlreadyExecutedError"],"tags":["graph","invokeai","state-error","queue"],"backgroundTag":"immutable-state-modification","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}