gastownhall/beads · error
add deps: final cycle check: %w
Error message
add deps: final cycle check: %w
What it means
After inserting edges individually, AddDependencies performs one combined CycleThroughEdges check over all non-scheduling pairs to catch cycles that only appear when the whole batch is considered. This error wraps a failure of that final query; a detected cycle instead yields the cycleErrorf message 'dependency cycle would be created: <path>'.
Source
Thrown at internal/storage/domain/dependency.go:776
var missingEndpoint *DependencyEndpointNotFoundError
if errors.As(err, &missingEndpoint) {
return BulkAddDepsResult{}, err
}
return BulkAddDepsResult{}, fmt.Errorf("add deps[%d]: insert: %w", i, err)
}
}
}
var pairs [][2]string
for _, dep := range deps {
if !types.IsSchedulingEdge(dep.Type) {
continue
}
pairs = append(pairs, [2]string{dep.IssueID, dep.DependsOnID})
}
if len(pairs) > 0 {
cyclePath, err := u.depRepo.CycleThroughEdges(ctx, pairs)
if err != nil {
return BulkAddDepsResult{}, fmt.Errorf("add deps: final cycle check: %w", err)
}
if cyclePath != "" {
return BulkAddDepsResult{}, cycleErrorf("add deps: dependency cycle would be created: %s", cyclePath)
}
}
return BulkAddDepsResult{Added: deps}, nil
}
// ValidateBlockingHierarchy passes the edge straight to the repository check
// AddDependencies runs per edge, so a caller re-running the gate at the end of
// a mixed request raises the identical *DependencyHierarchyConflictError rather
// than a second opinion about the same graph.
func (u *dependencyUseCaseImpl) ValidateBlockingHierarchy(ctx context.Context, dep *types.Dependency) error {
return u.depRepo.ValidateBlockingHierarchy(ctx, dep)
}
// CycleThroughEdges passes the pairs straight to the repository walk
// AddDependencies runs as its own final gate. The caller composes the refusal,View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause after 'final cycle check:'
- Retry with a healthy DB and non-canceled context
- Split very large batches into smaller requests to reduce traversal cost
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check: build the graph in memory and topologically verify the batch // adds no cycle before calling AddDependencies
Try / catch
if err != nil && strings.Contains(err.Error(), "final cycle check") {
// CycleThroughEdges query failed; inspect wrapped storage cause and retry
} Prevention
- Validate batch acyclicity client-side for large imports
- Split huge batches into smaller requests
- Keep the Dolt backend healthy and the context alive
When it happens
Trigger: Calling AddDependencies with at least one non-scheduling pair when depRepo.CycleThroughEdges(ctx, pairs) returns a storage/query error.
Common situations: Database errors during multi-edge graph traversal; context cancellation on large batches; locked or unavailable Dolt backend.
Related errors
- add deps[%d]: cycle check: %w
- loading deps for %s: %w
- failed to remove relates-to %s -> %s: %w
- failed to get dependencies for %s: %w
- db: DependencySQLRepository.HasCycle: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1eda4e2b0da0c3ff.
Report an issue: GitHub.