invoke-ai/InvokeAI · error · NodeAlreadyExecutedError

Node {node_id} has already been prepared or executed and can

Error message

Node {node_id} has already been prepared or executed and cannot be deleted

What it means

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.

Source

Thrown at invokeai/app/services/shared/graph.py:2860

        return True

    def _is_node_updatable(self, node_id: str) -> bool:
        # The node is updatable as long as it hasn't been prepared or executed
        return node_id not in self.source_prepared_mapping

    def add_node(self, node: BaseInvocation) -> None:
        self.graph.add_node(node)

    def update_node(self, node_id: str, new_node: BaseInvocation) -> None:
        if not self._is_node_updatable(node_id):
            raise NodeAlreadyExecutedError(
                f"Node {node_id} has already been prepared or executed and cannot be updated"
            )
        self.graph.update_node(node_id, new_node)

    def delete_node(self, node_id: str) -> None:
        if not self._is_node_updatable(node_id):
            raise NodeAlreadyExecutedError(
                f"Node {node_id} has already been prepared or executed and cannot be deleted"
            )
        self.graph.delete_node(node_id)

    def add_edge(self, edge: Edge) -> None:
        if not self._is_node_updatable(edge.destination.node_id):
            raise NodeAlreadyExecutedError(
                f"Destination node {edge.destination.node_id} has already been prepared or executed and cannot be linked to"
            )
        self.graph.add_edge(edge)

    def delete_edge(self, edge: Edge) -> None:
        if not self._is_node_updatable(edge.destination.node_id):
            raise NodeAlreadyExecutedError(
                f"Destination node {edge.destination.node_id} has already been prepared or executed and cannot have a source edge deleted"
            )
        self.graph.delete_edge(edge)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Delete the node before adding the graph to the queue, not after execution begins
  2. Clone/copy the graph, mutate the copy, and enqueue a new queue item instead of mutating the executed one
  3. Catch NodeAlreadyExecutedError and skip or log when the node is no longer needed
  4. Check _is_node_updatable (or track node state) before calling delete_node

Example fix

// before
execution.delete_node("node-1")  # raises if already run
// after
if execution._is_node_updatable("node-1"):
    execution.delete_node("node-1")
else:
    # mutate a fresh copy and enqueue a new item
    new_graph = execution._graph.model_copy(deep=True)
Defensive patterns

Strategy: validation

Validate before calling

if not execution._is_node_updatable(node_id):
    raise SkipMutation(f"node {node_id} already executed")
execution.delete_node(node_id)

Type guard

def can_mutate(execution, node_id: str) -> bool:
    return execution._is_node_updatable(node_id)

Try / catch

try:
    execution.delete_node(node_id)
except NodeAlreadyExecutedError as e:
    logger.warning("skipped delete on executed graph: %s", e)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/d4250d166da627f5. Report an issue: GitHub.