gastownhall/beads · error
add dep: hierarchy check: %w
Error message
add dep: hierarchy check: %w
What it means
This error wraps a failure from depRepo.ValidateBlockingHierarchy during dependency creation. The hierarchy check verifies blocking-dependency constraints; only recognized *DependencyHierarchyConflictError values are passed through as-is — any other repository error (SQL failure, context cancellation, unexpected backend state) is wrapped as 'add dep: hierarchy check:'.
Source
Thrown at internal/storage/domain/dependency.go:291
return fmt.Errorf("add dep: dep must not be nil")
}
if dep.IssueID == "" || dep.DependsOnID == "" {
return fmt.Errorf("add dep: IssueID and DependsOnID must be non-empty")
}
// Self-dependency guard mirrors issueops.CheckDependencyCycleInTx: it is
// checked BEFORE the cycle probe and for ALL dep types, and emits the
// dedicated self-dep message. A blocking self-edge otherwise trips HasCycle
// and would report the wrong (cycle) error (#4547 F-1).
if dep.IssueID == dep.DependsOnID {
return fmt.Errorf("%w: %s cannot depend on itself", ErrSelfDependency, dep.IssueID)
}
if err := u.depRepo.ValidateBlockingHierarchy(ctx, dep); err != nil {
var hierarchyConflict *DependencyHierarchyConflictError
if errors.As(err, &hierarchyConflict) {
return err
}
return fmt.Errorf("add dep: hierarchy check: %w", err)
}
if types.IsSchedulingEdge(dep.Type) {
cycle, err := u.depRepo.HasCycle(ctx, dep.IssueID, dep.DependsOnID)
if err != nil {
return fmt.Errorf("add dep: cycle check: %w", err)
}
if cycle {
// Match the embedded store's user-facing wording verbatim (no ids
// prefix) so gc code that string-matches this error behaves the same
// on both plumbings (#4547 F-1).
return ErrDependencyCycle
}
}
if err := u.depRepo.Insert(ctx, dep, actor, DepInsertOpts{UseWispsTable: useWisp, HierarchyValidated: true, CycleValidated: true, EmitEvent: true}); err != nil {
// The retype conflict is a user-facing error whose message already
// matches embedded verbatim; pass it through unwrapped so the CLI doesView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause after 'hierarchy check:' for the repository/driver error
- Retry on transient connection/deadline errors
- If the cause is a *DependencyHierarchyConflictError it is returned unwrapped — handle that separately as a domain conflict
- Verify hierarchy-related tables are intact (bd doctor / schema check) if errors persist
Example fix
// before
err := uc.AddDependency(ctx, dep, actor)
if err != nil { return err }
// after
err := uc.AddDependency(ctx, dep, actor)
var conflict *storage.DependencyHierarchyConflictError
if errors.As(err, &conflict) { return fmt.Errorf("hierarchy conflict: %s", conflict.Error()) }
if isTransient(err) { retry(...) }
return err Defensive patterns
Strategy: try-catch
Validate before calling
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel() // hierarchy traversal can be slow; avoid deadline surprises
if err := pingDB(ctx); err != nil { return err } Type guard
func isHierarchyConflict(err error) bool {
var hce *storage.DependencyHierarchyConflictError
return errors.As(err, &hce)
} Try / catch
err := uc.AddDependency(ctx, dep, actor)
if err != nil {
var hce *storage.DependencyHierarchyConflictError
if errors.As(err, &hce) { return err } // domain conflict, surface as-is
if isTransient(err) { return retryAdd(ctx, dep, actor) }
return fmt.Errorf("could not add dependency: %w", err)
} Prevention
- Check DB health before bulk dependency operations
- Distinguish hierarchy conflicts (expected) from infrastructure errors via errors.As
- Use generous timeouts for deep blocking-hierarchy validations
When it happens
Trigger: Calling AddDependency/AddWispDependency (with a non-scheduling or any dep reaching the check) where ValidateBlockingHierarchy fails with a non-hierarchy-conflict error: database query failure, connection loss, cancelled context, or an unexpected repository error inside the hierarchy validation.
Common situations: Database unavailable or timing out during hierarchy traversal; corrupted hierarchy data causing the validation query to error; context deadline exceeded while validating deep blocking chains.
Related errors
- db: DependencySQLRepository.ValidateBlockingHierarchy: dep m
- db: DependencySQLRepository.Insert: dep must not be nil
- db: DependencySQLRepository.Insert: IssueID must not be empt
- db: DependencySQLRepository.Insert: DependsOnID must not be
- db: Exists: id must not be empty
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/325e648408aaabd2.
Report an issue: GitHub.