gastownhall/beads · error
applyGraph: final cycle check: %w
Error message
applyGraph: final cycle check: %w
What it means
After all nodes and edges are inserted, applyGraph runs a final CycleThroughEdges check over the newly added scheduling edges; this error wraps a failure of that cycle-detection query itself (not the discovery of a cycle). The apply is aborted because the safety check could not complete.
Source
Thrown at internal/storage/domain/issue.go:1292
for _, nd := range node.Deps {
dep, err := types.NewGraphNodeDependency(keyToID[node.Key], nd.Type, nd.Target, keyToID)
if err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: %w", node.Key, err)
}
if (dep.Type == types.DepParentChild) != parentPhase {
continue
}
if err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp}); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: adding dep to %q: %w", node.Key, nd.Target, err)
}
if types.IsSchedulingEdge(dep.Type) {
newSchedulingEdges = append(newSchedulingEdges, [2]string{dep.IssueID, dep.DependsOnID})
}
}
}
}
if cyclePath, err := u.depRepo.CycleThroughEdges(ctx, newSchedulingEdges); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: final cycle check: %w", err)
} else if cyclePath != "" {
return GraphApplyResult{}, fmt.Errorf("applyGraph: dependency cycle would be created: %s", cyclePath)
}
// Pass 5 — apply deferred assignees.
for i, assignee := range pendingAssignees {
if assignee == "" {
continue
}
id := keyToID[plan.Nodes[i].Key]
if err := u.issueRepo.Update(ctx, id, map[string]any{"assignee": assignee}, actor, IssueTableOpts{UseWispsTable: useWisp}); err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: defer assignee: %w", plan.Nodes[i].Key, err)
}
}
return GraphApplyResult{IDs: keyToID}, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped error to see whether it's connectivity, timeout, or a query error.
- Retry the apply once the database is reachable (inserted edges may need rollback/cleanup if the apply is not transactional).
- For large graphs, reduce batch size or ensure the dep table indexes support the cycle query.
- Verify dependency table integrity (bd doctor / storage checks) if errors persist.
Defensive patterns
Strategy: retry
Validate before calling
// Cheap local cycle pre-check on the plan's scheduling edges before apply
if cycle := findCycle(planEdgesToAdjacency(plan.Edges)); cycle != "" {
return fmt.Errorf("plan has cycle: %s", cycle)
} Try / catch
if err := bd.GraphApply(ctx, plan); err != nil {
if strings.Contains(err.Error(), "final cycle check") {
// transient storage failure during validation — safe to retry after cleanup
return retryWithBackoff(func() error { return bd.GraphApply(ctx, plan) })
}
return err
} Prevention
- Ensure stable DB connectivity for the duration of apply
- Keep graphs small enough for fast cycle queries
- Run bd doctor storage checks if cycle-check errors recur
When it happens
Trigger: CycleThroughEdges returning a query/storage error — Dolt query failure, connectivity problem, or an internal error traversing the dependency graph — during the final validation pass of graph apply.
Common situations: Database connectivity drops mid-apply; very large graphs timing out the cycle query; corrupted or inconsistent dependency tables; running against a Dolt server under load.
Related errors
- applyGraph: edge %d %s->%s: checking planned blocking cycle:
- get molecule children: %w
- failed to get issue %s: %w
- failed to remove relates-to %s -> %s: %w
- failed to get epic: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/844ffee26422117f.
Report an issue: GitHub.