gastownhall/beads · error
final cycle check failed (no edges added): %w
Error message
final cycle check failed (no edges added): %w
What it means
During ExecuteAddDependencies' end gate, checkAddedEdgesForCycles builds the full scheduling graph inside the transaction via AppendSchedulingGraphInTx; if that graph-load query fails, the whole add is aborted with this wrapped error. No edges have been added at this point, so the transaction is purely failed by an infrastructure/query problem, not by a real cycle. The %w preserves the underlying driver error for errors.As/errors.Is inspection.
Source
Thrown at internal/storage/issueops/dependency_editor.go:227
// them off entirely, so this is the check that actually holds the invariant.
//
// The message is built through domain.NewCycleError so it errors.Is-matches
// ErrDependencyCycle while rendering byte-for-byte what the direct bulk path
// already prints.
func checkAddedEdgesForCycles(ctx context.Context, tx *sql.Tx, edges []publicops.DependencyEdge) error {
var pairs [][2]string
for _, edge := range edges {
if !types.IsSchedulingEdge(edge.Type) {
continue
}
pairs = append(pairs, [2]string{edge.IssueID, edge.DependsOnID})
}
if len(pairs) == 0 {
return nil
}
graph := make(map[string][]string)
if err := AppendSchedulingGraphInTx(ctx, tx, cycleDetectionTables(), graph); err != nil {
return fmt.Errorf("final cycle check failed (no edges added): %w", err)
}
if cyclePath := CycleThroughEdgesInGraph(graph, pairs); cyclePath != "" {
return domain.NewCycleError("dependency cycle would be created: %s (no edges added; run 'bd dep cycles' for analysis)", cyclePath)
}
return nil
}
// ExecuteRemoveDependency removes one edge in tx and reports the durable
// tables changed.
//
// A missing edge reports Removed false and NO changed tables, which is how the
// callers spell "commit nothing": removing an edge that was never there leaves
// the graph it already had, and a history entry for it would be a commit with
// nothing in it.
func ExecuteRemoveDependency(ctx context.Context, tx *sql.Tx, request publicops.RemoveDependencyRequest) (publicops.RemoveDependencyResult, ChangedTables, error) {
// Routing is READ here rather than pinned, unlike the add. A removal
// cannot put an edge anywhere, so pinning it would only mean failing to
// remove an edge the caller named — and the staging has to name the tablesView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause with errors.As to identify the driver error (connection lost, lock timeout, etc.) and address that root cause.
- Retry the whole ExecuteAddDependencies operation in a fresh transaction — the failed tx rolled back and left no edges added.
- Check database connectivity and server health if the error recurs; verify no competing transaction holds long locks on the dependency tables.
Defensive patterns
Strategy: retry
Try / catch
err := editor.ExecuteAddDependencies(ctx, req)
if err != nil {
var derr error
if errors.As(err, &derr) && strings.Contains(err.Error(), "final cycle check failed") {
// tx rolled back with no edges added; safe to retry whole operation
return retryOperation(ctx, req)
}
return err
} Prevention
- Keep database connections healthy (keepalives, sane timeouts) since the check runs mid-transaction.
- Avoid concurrent long transactions on the dependency tables to reduce lock contention.
- Retry idempotently: no edges are added on this failure, so a whole-operation retry is safe.
When it happens
Trigger: Any failure of the tx.QueryContext-backed AppendSchedulingGraphInTx while loading cycle-detection tables (cycleDetectionTables) mid-transaction — e.g. a database connection drop, lock timeout, or driver error during ExecuteAddDependencies or runEndGate.
Common situations: Dolt/server connection interrupted mid-transaction; database under heavy lock contention from concurrent writers; transient driver errors during long graph loads on large issue graphs.
Related errors
- applyGraph: final cycle check: %w
- applyGraph: edge %d %s->%s: checking planned blocking cycle:
- get dependency records: rows: %w
- ErrTransaction
- ErrQuery
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/cb7662dd8208b2fa.
Report an issue: GitHub.