invoke-ai/InvokeAI · error · NodeAlreadyExecutedError

Destination node {edge.destination.node_id} has already been

Error message

Destination node {edge.destination.node_id} has already been prepared or executed and cannot be linked to

What it means

GraphExecution.add_edge throws NodeAlreadyExecutedError when the edge's destination node has already been prepared or executed. Adding an edge to a finished node would retroactively change execution inputs, so it is forbidden. Mutate the graph before it is queued or enqueue a modified copy.

Source

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

        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. Add all edges before enqueueing the graph
  2. Create a new graph/queue item with the desired edge instead of editing the executed session
  3. Catch NodeAlreadyExecutedError and handle (skip edge, notify user)
  4. Guard with _is_node_updatable(edge.destination.node_id) before add_edge

Example fix

// before
execution.add_edge(edge)  # raises if destination already executed
// after
if execution._is_node_updatable(edge.destination.node_id):
    execution.add_edge(edge)
else:
    g = execution._graph.model_copy(deep=True)
    g.add_edge(edge)
    # enqueue g as a new queue item
Defensive patterns

Strategy: validation

Validate before calling

if not execution._is_node_updatable(edge.destination.node_id):
    raise SkipMutation("destination already executed")
execution.add_edge(edge)

Type guard

def edge_target_mutable(execution, edge: Edge) -> bool:
    return execution._is_node_updatable(edge.destination.node_id)

Try / catch

try:
    execution.add_edge(edge)
except NodeAlreadyExecutedError:
    enqueue_new_graph_with_edge(graph, edge)

Prevention

When it happens

Trigger: Calling GraphExecution.add_edge(edge) where edge.destination.node_id is in the prepared/executed node list (_is_node_updatable returns False).

Common situations: Wiring late outputs into already-run nodes during a live session, editing graphs over the websocket while execution is in progress, or loop-style graphs that try to feed results back into executed nodes.

Related errors


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