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 have a source edge deleted

What it means

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.

Source

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

        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. Remove the edge before the graph is queued for execution
  2. Copy the graph, delete the edge on the copy, and enqueue the new graph
  3. Catch NodeAlreadyExecutedError and treat the edge as already-locked
  4. Check _is_node_updatable(edge.destination.node_id) before delete_edge

Example fix

// before
execution.delete_edge(edge)  # raises if destination already executed
// after
if execution._is_node_updatable(edge.destination.node_id):
    execution.delete_edge(edge)
Defensive patterns

Strategy: validation

Validate before calling

if not execution._is_node_updatable(edge.destination.node_id):
    return  # edge is locked to an executed node
execution.delete_edge(edge)

Type guard

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

Try / catch

try:
    execution.delete_edge(edge)
except NodeAlreadyExecutedError as e:
    logger.info("edge locked: %s", e)

Prevention

When it happens

Trigger: Calling GraphExecution.delete_edge(edge) where edge.destination.node_id has already been prepared or executed.

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

Related errors


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