microsoft/autogen · error · ValueError
Cycle detected without exit condition: {' -> '.join(cycle_no
Error message
Cycle detected without exit condition: {' -> '.join(cycle_nodes + cycle_nodes[:1])} What it means
Raised by DiGraph.has_cycles_with_exit during graph validation when a directed cycle is found in which every edge is unconditional (neither a textual condition nor a condition_function). An unconditional cycle has no way to exit, so the chat would loop forever; validation therefore rejects it. Cycles are allowed only when at least one edge in the cycle provides an exit condition.
Source
Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_graph/_digraph_group_chat.py:183
visited.add(node_name)
rec_stack.add(node_name)
path.append(node_name)
cycle = False
for edge in self.nodes[node_name].edges:
target = edge.target
if target not in visited:
if dfs(target):
cycle = True
elif target in rec_stack:
# Found a cycle → extract the cycle
cycle_start_index = path.index(target)
cycle_nodes = path[cycle_start_index:]
cycle_edges: List[DiGraphEdge] = []
for n in cycle_nodes:
cycle_edges.extend(self.nodes[n].edges)
if all(edge.condition is None and edge.condition_function is None for edge in cycle_edges):
raise ValueError(
f"Cycle detected without exit condition: {' -> '.join(cycle_nodes + cycle_nodes[:1])}"
)
cycle = True # Found cycle, but it has an exit condition
rec_stack.remove(node_name)
path.pop()
return cycle
has_cycle = False
for node in self.nodes:
if node not in visited:
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)."""View on GitHub (pinned to 027ecf0a37)
Solutions
- Add condition="..." or condition_function=... to at least one edge in the cycle (typically the back-edge), describing when to leave the loop.
- Alternatively break the cycle with a conditional edge to an exit/leaf node.
- If the loop is intentionally bounded, also consider max_turns on the team as a safety net (though the structural fix is still required).
Example fix
// before builder.add_edge(reviewer, reviser) builder.add_edge(reviser, reviewer) # unconditional cycle -> error // after builder.add_edge(reviewer, reviser, condition="revision needed") builder.add_edge(reviser, reviewer, condition_function=lambda m: "approved" not in str(m).lower()) builder.add_edge(reviewer, finalizer, condition="approved")
Defensive patterns
Strategy: validation
Validate before calling
def cycle_edges_have_exit(builder: DiGraphBuilder) -> bool:
try:
builder.build().graph_validate()
return True
except ValueError as e:
if "Cycle detected without exit condition" in str(e):
return False
raise Type guard
def edge_is_conditional(edge) -> bool:
return edge.condition is not None or edge.condition_function is not None Try / catch
try:
flow = GraphFlow(participants, graph_builder=builder)
except ValueError as e:
if "Cycle detected without exit condition" in str(e):
# add condition/condition_function to at least one edge in the reported cycle
... Prevention
- Always attach a condition or condition_function to back-edges in loops.
- Unit-test graph validation for every workflow graph you author.
- Model loops as: entry -> [work] -> conditional back-edge, plus conditional exit edge to a leaf.
When it happens
Trigger: Using DiGraphBuilder.add_edge in a loop (e.g. reviewer -> reviser -> reviewer) without condition= or condition_function= on any edge of the cycle; converting a linear workflow to a cyclic one while forgetting to add the exit condition; typos making a condition evaluate falsy at build time is not the issue here — the check is purely structural (condition is None).
Common situations: Draft/review/revise loops in GraphFlow; porting workflows from other frameworks where loops are bounded externally; adding a 'back edge' for retries without specifying when to stop.
Related errors
- Graph must have at least one start node
- Graph must have at least one leaf node
- All agents in the workflow must be in the group chat.
- Graph has no nodes.
- Node '{node.name}' has a mix of conditional and unconditiona
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/faaa39bf1fefe9e4.
Report an issue: GitHub.