gastownhall/beads · error
dependency graph: scan %s: %w
Error message
dependency graph: scan %s: %w
What it means
appendDependencyGraphInTx failed scanning a row of a dependency table into (issue_id, depends_on_id, type). A scan error means column types or nullability differ from what the query expects; the function closes the rows and wraps the error with the table name for diagnosis.
Source
Thrown at internal/storage/issueops/cycles.go:108
// 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
}
// CycleThroughEdgesInGraph reports a rendered cycle that traverses
// one of the new edges (issueID -> dependsOnID pairs), or "" when no new edge
// lies on a cycle. An edge u -> v is on a cycle exactly when u is reachable
// from v, so this is precise where cycle enumeration is not: a DFS-basedView on GitHub (pinned to 71377f2769)
Solutions
- Find and fix the offending NULL/malformed rows in the named dependency table
- Align the schema with the version of beads in use (re-run migrations)
- If an upgrade caused it, check release notes for dependency-table schema changes
Example fix
// before SELECT issue_id, depends_on_id, type FROM dependencies -- NULL rows present // after UPDATE dependencies SET type='blocks' WHERE type IS NULL; -- then retry
Defensive patterns
Strategy: validation
Validate before calling
// detect malformed rows before creating dependencies
rows, _ := db.Query("SELECT issue_id, depends_on_id, type FROM dependencies WHERE issue_id IS NULL OR depends_on_id IS NULL OR type IS NULL")
// if any rows returned, repair them first Try / catch
if err != nil && strings.HasPrefix(err.Error(), "dependency graph: scan ") {
// locate NULL rows in the named table, repair, then retry
} Prevention
- Enforce NOT NULL on dependency columns
- Repair data after version upgrades
- Validate imported dependency rows before writing them
When it happens
Trigger: A dependency row has NULL in issue_id/depends_on_id/type or an unexpected column type, so rows.Scan fails while iterating during graph assembly.
Common situations: Schema mismatch after version upgrade (columns added/renamed/nullable); hand-edited or imported rows with NULL dependency fields; corruption from a failed migration.
Related errors
- failed to scan federation peer: %w
- failed to scan comment: %w
- failed to get issue from %s: %w
- db: ListRemotes: scan: %w
- scan wisp dependent: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/898f65c401e9f366.
Report an issue: GitHub.