gastownhall/beads · error

failed to check for dependency cycle: %w

Error message

failed to check for dependency cycle: %w

What it means

Wraps an infrastructure error from WouldCreateSchedulingCycleInTx while CheckDependencyCycleInTx is determining whether the new edge would form a cycle. This is not a detected cycle (that returns domain.ErrDependencyCycle); it means the cycle-detection queries themselves failed, so the check could not be performed.

Source

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

		  )
	`, sourceTable, targetTable), source, target)
	return err
}

// CheckDependencyCycleInTx rejects self-dependencies and cycles across the
// combined blocks, conditional-blocks, and parent-child graph before insert.
// The caller may pass a restricted depTables list for a known storage bucket;
// nil uses all dependency tables.
func CheckDependencyCycleInTx(ctx context.Context, tx DBTX, dep *types.Dependency, depTables []string) error {
	if dep.IssueID == dep.DependsOnID {
		return fmt.Errorf("%w: %s cannot depend on itself", domain.ErrSelfDependency, dep.IssueID)
	}
	if !types.IsSchedulingEdge(dep.Type) {
		return nil
	}
	wouldCycle, err := WouldCreateSchedulingCycleInTx(ctx, tx, dep.IssueID, dep.DependsOnID, depTables)
	if err != nil {
		return fmt.Errorf("failed to check for dependency cycle: %w", err)
	}
	if wouldCycle {
		return domain.ErrDependencyCycle
	}
	return nil
}

// WouldCreateSchedulingCycleInTx reports whether adding issueID -> dependsOnID
// would close a cycle in the combined scheduling graph. It is shared by the
// classic and domain storage stacks so both traverse the same dependency types
// and typed target columns.
func WouldCreateSchedulingCycleInTx(ctx context.Context, tx DBTX, issueID, dependsOnID string, depTables []string) (bool, error) {
	if len(depTables) == 0 {
		depTables = cycleDetectionTables()
	}
	var reachable int
	query := cycleReachabilityQuery(depTables)
	if err := tx.QueryRowContext(ctx, query, dependsOnID, issueID).Scan(&reachable); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause (%w) for the real SQL failure and fix that
  2. Verify the depTables argument names valid storage buckets (or pass nil for all tables)
  3. Retry once the database is healthy; the check is read-only so a retry is safe
  4. Repair dangling dependency rows if traversal errors point at missing referenced issues

Example fix

// before
if err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, []string{"dep_links"}); err != nil {
	return err
}
// after: use the default tables (nil = all dependency tables)
if err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, nil); err != nil {
	if errors.Is(err, domain.ErrDependencyCycle) {
		return err
	}
	return fmt.Errorf("cycle check infra failure: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// check both endpoints exist and tables are valid before cycle check
if !exists(ctx, db, dep.IssueID) || !exists(ctx, db, dep.DependsOnID) {
	return errors.New("dependency endpoint missing")
}
if depTables != nil {
	for _, t := range depTables {
		if !validDepTable(t) { return fmt.Errorf("unknown dep table %q", t) }
	}
}

Type guard

func isCycleCheckInfraFailure(err error) bool {
	return err != nil &&
		!errors.Is(err, domain.ErrDependencyCycle) &&
		strings.Contains(err.Error(), "failed to check for dependency cycle")
}

Try / catch

err := issueops.CheckDependencyCycleInTx(ctx, tx, dep, nil)
switch {
case errors.Is(err, domain.ErrDependencyCycle):
	return err // genuine cycle
case err != nil:
	return retryWithBackoff(op) // infra failure, read-only check is safe to retry
}

Prevention

When it happens

Trigger: CheckDependencyCycleInTx called with a scheduling-edge dependency where the underlying graph traversal queries in WouldCreateSchedulingCycleInTx error out — DB unreachable, transaction aborted, invalid depTables list, or corrupt rows in the dependency tables.

Common situations: Transient database failures during a dep-add; wrong depTables argument filtering to a nonexistent bucket; migration drift leaving dependency rows referencing missing issues.

Related errors


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