gastownhall/beads · error

dependency graph: query %s: %w

Error message

dependency graph: query %s: %w

What it means

appendDependencyGraphInTx failed querying a dependency table (per depTable in the given list) while assembling the blocking/scheduling dependency graph for cycle detection. The table name is interpolated into the message; the driver error is wrapped. This aborts the cycle-check, and the caller treats graph-build failure as fatal for the operation.

Source

Thrown at internal/storage/issueops/cycles.go:102

func AppendBlockingGraphInTx(ctx context.Context, tx DBTX, depTables []string, graph map[string][]string) error {
	return appendDependencyGraphInTx(ctx, tx, depTables, graph, false)
}

// AppendSchedulingGraphInTx adds blocks, conditional-blocks, and parent-child
// edges to graph for validating mutations against the combined scheduling
// graph. DetectCycles intentionally continues to use AppendBlockingGraphInTx.
func AppendSchedulingGraphInTx(ctx context.Context, tx DBTX, depTables []string, graph map[string][]string) error {
	return appendDependencyGraphInTx(ctx, tx, depTables, graph, true)
}

func appendDependencyGraphInTx(ctx context.Context, tx DBTX, depTables []string, graph map[string][]string, includeParentChild bool) error {
	for _, depTable := range depTables {
		rows, err := tx.QueryContext(ctx, fmt.Sprintf(`
			SELECT issue_id, %s AS depends_on_id, type
			FROM %s
		`, DepTargetExpr, depTable))
		if err != nil {
			return fmt.Errorf("dependency graph: query %s: %w", depTable, err)
		}
		for rows.Next() {
			var issueID, dependsOnID, depType string
			if err := rows.Scan(&issueID, &dependsOnID, &depType); err != nil {
				_ = rows.Close()
				return fmt.Errorf("dependency graph: scan %s: %w", depTable, err)
			}
			t := types.DependencyType(depType)
			if t == types.DepBlocks || t == types.DepConditionalBlocks || (includeParentChild && t == types.DepParentChild) {
				graph[issueID] = append(graph[issueID], dependsOnID)
			}
		}
		_ = rows.Close()
		if err := rows.Err(); err != nil {
			return fmt.Errorf("dependency graph: rows %s: %w", depTable, err)
		}
	}
	return nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error and the named table to find the storage-level cause
  2. Apply pending migrations so all dependency tables exist
  3. Retry the operation in a fresh transaction; reduce concurrent dependency writes during cycle checks

Example fix

// before
// retry blindly
// after
if strings.Contains(err.Error(), "no such table") { runMigrations(); retry() }
Defensive patterns

Strategy: retry

Try / catch

if err := AddDependency(ctx, ...); err != nil {
    if strings.HasPrefix(err.Error(), "dependency graph: query ") {
        // backoff and retry the operation in a new transaction
    }
    return err
}

Prevention

When it happens

Trigger: QueryContext over a dependency table fails during AppendBlockingGraphInTx / AppendSchedulingGraphInTx — missing table, locked DB, connection loss mid-cycle-check.

Common situations: Schema drift (dependency table absent after partial migration); storage contention while another transaction mutates dependencies; transient driver failures on large graphs.

Related errors


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