microsoft/autogen · error · ValueError

Graph must have at least one start node

Error message

Graph must have at least one start node

What it means

Raised by DiGraph.graph_validate when the graph has nodes but no start node — a node with no incoming edges. Execution begins at start nodes, so a graph where every node has an incoming edge (e.g. everything is in a cycle or all edges were added in a closed chain) has no valid entry point and is rejected.

Source

Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_graph/_digraph_group_chat.py:213

                if dfs(node):
                    has_cycle = True

        return has_cycle

    def get_has_cycles(self) -> bool:
        """Indicates if the graph has at least one cycle (with valid exit conditions)."""
        if self._has_cycles is None:
            self._has_cycles = self.has_cycles_with_exit()

        return self._has_cycles

    def graph_validate(self) -> None:
        """Validate graph structure and execution rules."""
        if not self.nodes:
            raise ValueError("Graph has no nodes.")

        if not self.get_start_nodes():
            raise ValueError("Graph must have at least one start node")

        if not self.get_leaf_nodes():
            raise ValueError("Graph must have at least one leaf node")

        # Outgoing edge condition validation (per node)
        for node in self.nodes.values():
            # Check that if a node has an outgoing conditional edge, then all outgoing edges are conditional
            has_condition = any(
                edge.condition is not None or edge.condition_function is not None for edge in node.edges
            )
            has_unconditioned = any(edge.condition is None and edge.condition_function is None for edge in node.edges)
            if has_condition and has_unconditioned:
                raise ValueError(f"Node '{node.name}' has a mix of conditional and unconditional edges.")

        # Validate activation conditions across all edges in the graph
        self._validate_activation_conditions()

        self._has_cycles = self.has_cycles_with_exit()

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Designate an entry node with no incoming edges (builder.set_start_node(first_agent)) and make sure no edge targets it.
  2. For loops, add a dedicated starter node whose only edge leads into the cycle.
  3. Inspect builder.nodes and each node's incoming edges to confirm exactly which nodes qualify as start nodes.

Example fix

// before
builder.add_edge(reviewer, reviser)
builder.add_edge(reviser, reviewer)  # no start node possible

// after
builder.add_edge(triage, reviewer)
builder.add_edge(reviewer, reviser, condition="needs work")
builder.add_edge(reviser, reviewer, condition_function=lambda m: not _done(m))
builder.set_start_node(triage)
Defensive patterns

Strategy: validation

Validate before calling

graph = builder.build()
if not graph.get_start_nodes():
    raise ValueError("No start node: ensure one node has no incoming edges and call set_start_node")
flow = GraphFlow(participants, graph_builder=builder)

Type guard

def has_start_node(incoming: dict[str, int]) -> bool:
    return any(count == 0 for count in incoming.values())

Try / catch

try:
    flow = GraphFlow(participants, graph_builder=builder)
except ValueError as e:
    if "at least one start node" in str(e):
        # add an entry node with no incoming edges and set_start_node on it
        ...

Prevention

When it happens

Trigger: Creating only cyclic edges (A->B, B->A) so every node has an incoming edge; explicitly calling set_start_node on a node that nonetheless receives an incoming edge later, disqualifying it; building a graph where the intended entry node was accidentally given a parent.

Common situations: Cyclic review loops with no designated entry; forgetting to branch the first node out; refactoring that adds an edge into the former start node.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/2f2b133c2b0a75f8. Report an issue: GitHub.