gastownhall/beads · error
get dependencies: scan: %w
Error message
get dependencies: scan: %w
What it means
Wraps a rows.Scan failure while decoding a (depends_on_id, type) pair inside GetDependenciesWithMetadataInTx. The dependency query succeeded but a row's values cannot be scanned into the two string fields.
Source
Thrown at internal/storage/issueops/dependencies.go:1116
//nolint:gosec // G201: table names come from hardcoded constants
func GetDependenciesWithMetadataInTx(ctx context.Context, tx DBTX, issueID string) ([]*types.IssueWithDependencyMetadata, error) {
type depMeta struct {
depID, depType string
}
// Query both dependency tables to find all dependencies.
var deps []depMeta
for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
rows, err := tx.QueryContext(ctx, fmt.Sprintf(
`SELECT %s AS depends_on_id, type FROM %s WHERE issue_id = ?`, DepTargetExpr, depTable), issueID)
if err != nil {
return nil, fmt.Errorf("get dependencies from %s: %w", depTable, err)
}
for rows.Next() {
var d depMeta
if scanErr := rows.Scan(&d.depID, &d.depType); scanErr != nil {
_ = rows.Close()
return nil, fmt.Errorf("get dependencies: scan: %w", scanErr)
}
deps = append(deps, d)
}
_ = rows.Close()
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("get dependencies: rows from %s: %w", depTable, err)
}
}
if len(deps) == 0 {
return nil, nil
}
// Fetch all dependency target issues.
ids := make([]string, len(deps))
for i, d := range deps {
ids[i] = d.depID
}View on GitHub (pinned to 71377f2769)
Solutions
- Find and fix the offending dependency row (NULL type or dangling depends_on reference)
- Clean up orphaned dependency rows referencing deleted issues
- Align schema version with the binary (run migrations) so column types match the scanner
Defensive patterns
Strategy: validation
Validate before calling
// Data preflight: find dependency rows that will fail the (string,string) scan: rows, err := db.QueryContext(ctx, `SELECT issue_id FROM dependencies WHERE type IS NULL`) rows2, err2 := db.QueryContext(ctx, `SELECT issue_id FROM wisp_dependencies WHERE type IS NULL`) // Any results indicate corrupt rows to repair before fetching dependencies.
Try / catch
deps, err := ops.GetDependenciesWithMetadataInTx(ctx, tx, issueID)
if err != nil && strings.Contains(err.Error(), "get dependencies: scan") {
// Deterministic — repair data instead of retrying:
return fmt.Errorf("corrupt dependency row (NULL type/target); run repair: %w", err)
} Prevention
- Enforce NOT NULL on dep_type/depends_on columns in migrations
- Use library APIs (not manual SQL) to insert dependencies
- Clean orphaned dependency rows when issues are deleted externally
- Run integrity checks after version upgrades or crashes
When it happens
Trigger: rows.Scan(&d.depID, &d.depType) fails — the type column or the DepTargetExpr-derived depends_on_id is NULL or of an unexpected type in a dependencies/wisp_dependencies row.
Common situations: Rows inserted with NULL dep_type by older versions or manual edits; DepTargetExpr returning unexpected shapes (e.g. NULL for dangling references after a partial delete).
Related errors
- db: ChildCounterSQLRepository.NextChildID: scan: %w
- db: CommentSQLRepository.CountsByIssueIDs: scan: %w
- db: CommentSQLRepository.ListByIssueIDs: scan: %w
- db: LabelSQLRepository.List: scan: %w
- db: LabelSQLRepository.ListByIssueIDs: scan: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/881320eee11ff04f.
Report an issue: GitHub.