HKUDS/Vibe-Trading · error · ValueError

Cycle detected in task DAG: {' -> '.join(cycle)}

Error message

Cycle detected in task DAG: {' -> '.join(cycle)}

What it means

During DFS cycle detection in validate_dag, reaching a GRAY (in-progress) node means the dependency graph has a cycle; the error lists the exact path, e.g. 'a -> b -> c -> a'. Cyclic task graphs can never be scheduled.

Source

Thrown at agent/src/swarm/task_store.py:189

    path: list[str] = []

    def dfs(node: str) -> None:
        """DFS traversal to detect back edges.

        Args:
            node: Current node ID.

        Raises:
            ValueError: If a cycle is detected.
        """
        color[node] = GRAY
        path.append(node)

        for neighbor in graph.get(node, []):
            if color[neighbor] == GRAY:
                cycle_start = path.index(neighbor)
                cycle = path[cycle_start:] + [neighbor]
                raise ValueError(
                    f"Cycle detected in task DAG: {' -> '.join(cycle)}"
                )
            if color[neighbor] == WHITE:
                dfs(neighbor)

        path.pop()
        color[node] = BLACK

    for tid in all_ids:
        if color[tid] == WHITE:
            dfs(tid)


def topological_layers(tasks: list[SwarmTask]) -> list[list[str]]:
    """Kahn's algorithm topological layering; tasks in the same layer can run in parallel.

    Args:
        tasks: List of SwarmTask (must be a valid acyclic DAG).

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Break the cycle at the edge that points backward (usually the last-added dependency)
  2. Move shared work into a separate upstream task both nodes depend on
  3. Re-run validate_dag after every depends_on edit

Example fix

# before
SwarmTask(id='a', depends_on=['b']); SwarmTask(id='b', depends_on=['a'])
# after
SwarmTask(id='a', depends_on=[]); SwarmTask(id='b', depends_on=['a'])
Defensive patterns

Strategy: validation

Validate before calling

validate_dag(tasks)  # run first; reports the exact cycle path

Try / catch

try:
    validate_dag(tasks)
except ValueError as e:
    if 'Cycle detected' in str(e): print(e); break the reported loop
    else: raise

Prevention

When it happens

Trigger: Task A depends on B while B depends on A; longer loops introduced by adding a 'final' task that an early task depends on.

Common situations: Incrementally adding an aggregation step and wiring it as both consumer and producer; copy-paste editing of depends_on lists.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/7f4bcd463a394cb4. Report an issue: GitHub.