gastownhall/beads · error

failed to check blocker ancestry: %w

Error message

failed to check blocker ancestry: %w

What it means

Wraps an error from isAncestorInTx while CheckBlockingHierarchyInTx checks whether the blocker is an ancestor of the dependent issue in the hierarchy. This is not the hierarchy-conflict result itself (that is a DependencyHierarchyConflictError); it means the ancestry lookup query failed, so the hierarchy validation could not complete.

Source

Thrown at internal/storage/issueops/dependencies.go:532

	return []string{"dependencies", "wisp_dependencies"}
}

// CheckBlockingHierarchyInTx rejects blocking dependencies between an issue
// and its own ancestor or descendant. Cross-prefix/external targets must be
// filtered by the caller because no local hierarchy can connect them.
func CheckBlockingHierarchyInTx(ctx context.Context, tx DBTX, dep *types.Dependency, depTables []string) error {
	if dep.Type != types.DepBlocks && dep.Type != types.DepConditionalBlocks {
		return nil
	}
	if dep.IssueID == dep.DependsOnID {
		return nil // The dedicated self-dependency check owns this error.
	}
	if len(depTables) == 0 {
		depTables = cycleDetectionTables()
	}
	blockerIsAncestor, err := isAncestorInTx(ctx, tx, dep.IssueID, dep.DependsOnID, depTables)
	if err != nil {
		return fmt.Errorf("failed to check blocker ancestry: %w", err)
	}
	if blockerIsAncestor {
		return &domain.DependencyHierarchyConflictError{
			IssueID: dep.IssueID, BlockerID: dep.DependsOnID, BlockerIsAncestor: true,
		}
	}
	blockerIsDescendant, err := isAncestorInTx(ctx, tx, dep.DependsOnID, dep.IssueID, depTables)
	if err != nil {
		return fmt.Errorf("failed to check blocker ancestry: %w", err)
	}
	if blockerIsDescendant {
		return &domain.DependencyHierarchyConflictError{
			IssueID: dep.IssueID, BlockerID: dep.DependsOnID,
		}
	}
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause for the underlying SQL error and address it
  2. Retry the operation; the ancestry check is read-only and the tx rolls back cleanly
  3. Validate parent chains of both issues (no dangling parent IDs) before adding the dependency
  4. Check for lock contention from concurrent hierarchy mutations and serialize writes

Example fix

// before
if err := issueops.CheckBlockingHierarchyInTx(ctx, tx, dep, nil); err != nil {
	return err
}
// after
if err := issueops.CheckBlockingHierarchyInTx(ctx, tx, dep, nil); err != nil {
	var hier *domain.DependencyHierarchyConflictError
	if errors.As(err, &hier) {
		return err // genuine hierarchy conflict
	}
	return fmt.Errorf("hierarchy check unavailable, deferring dep add: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure both issues have resolvable parent chains before hierarchy check
if danglingParent(ctx, db, dep.IssueID) || danglingParent(ctx, db, dep.DependsOnID) {
	return errors.New("cannot validate hierarchy: dangling parent reference")
}

Type guard

func isAncestryInfraFailure(err error) bool {
	var hier *domain.DependencyHierarchyConflictError
	return err != nil && !errors.As(err, &hier) &&
		strings.Contains(err.Error(), "failed to check blocker ancestry")
}

Try / catch

err := issueops.CheckBlockingHierarchyInTx(ctx, tx, dep, nil)
var hier *domain.DependencyHierarchyConflictError
switch {
case errors.As(err, &hier):
	return err // genuine hierarchy conflict
case err != nil:
	return retryWithBackoff(op) // ancestry lookup failed, not a conflict
}

Prevention

When it happens

Trigger: CheckBlockingHierarchyInTx invoked (via addDependencyInTx, PersistDependenciesWithOptionsResult, or runEndGate) with empty depTables defaulted to cycleDetectionTables, and isAncestorInTx errors on its traversal — DB failure, aborted tx, or corrupted hierarchy rows.

Common situations: Database connectivity loss during dep-add or an end-gate run; concurrent renames of issues invalidating traversal mid-tx; malformed parent links in the issues table.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/7c41203d58b5c2c4. Report an issue: GitHub.