gastownhall/beads · error
scan neighbor: %w
Error message
scan neighbor: %w
What it means
While streaming neighbor rows, rows.Scan failed to decode the two string columns (issue_id, depends_on_id) returned by the neighbors query. Like the dependents scan error, this indicates the row shape deviates from what the query assumes — typically NULLs or a non-string column produced by the DepTargetExpr expression. Rows are closed before returning and the delete aborts.
Source
Thrown at internal/storage/issueops/delete_role.go:278
inClause, args := buildSQLInClause(ids[i:end])
doubled := append(append([]interface{}{}, args...), args...)
for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
rows, err := tx.QueryContext(ctx,
fmt.Sprintf(`SELECT issue_id, %s AS depends_on_id FROM %s WHERE issue_id IN (%s) OR %s`,
DepTargetExpr, depTable, inClause, depTargetIn("", inClause)),
doubled...)
if err != nil {
if optionalBlockedTable(depTable) && isTableNotExistError(err) {
continue
}
return nil, fmt.Errorf("query neighbors from %s: %w", depTable, err)
}
for rows.Next() {
var source, target string
if err := rows.Scan(&source, &target); err != nil {
_ = rows.Close()
return nil, fmt.Errorf("scan neighbor: %w", err)
}
for _, candidate := range [2]string{source, target} {
if candidate == "" || deleting[candidate] {
continue
}
neighborIDs[candidate] = true
}
}
_ = rows.Close()
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate neighbors from %s: %w", depTable, err)
}
}
}
if len(neighborIDs) == 0 {
return nil, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Locate and repair the offending row (NULL issue_id or NULL target in the named dependency table)
- Check whether DepTargetExpr was modified and still returns a plain string
- Confirm the dependency tables were not written by an incompatible schema version
- Re-run the delete after the data fix; it fails on the same row until repaired
Example fix
// before: row with NULL issue_id crashes the scan // after: clean orphaned edges DELETE FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL;
Defensive patterns
Strategy: validation
Validate before calling
// pre-audit for malformed neighbor edges
rows, _ := db.Query("SELECT issue_id, target_id FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL")
// fix any hits before deleting, or Scan will fail on them Try / catch
if err != nil && strings.Contains(err.Error(), "scan neighbor") {
// locate the malformed dependency row and repair, then re-run delete
} Prevention
- Route all edge writes through the library API
- Integrity-check dependency tables after imports or manual surgery
- Keep DepTargetExpr unmodified unless you also fix scan arity/types
- Align schema versions across all writer processes
When it happens
Trigger: deleteNeighborsInTx iterates rows from the dependencies/wisp_dependencies neighbor query and Scan(&source, &target) errors — NULL column values, driver type coercion failure, or altered SELECT arity.
Common situations: Hand-edited or legacy dependency rows with NULL issue_id/target; custom or drifted DepTargetExpr; backend driver returning columns in unexpected types.
Related errors
- scan dependent: %w
- failed to scan peer for migration: %w
- scan inbound dependency: %w
- get dependents: scan: %w
- get dependency counts: scan blocker: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a6eb1b90f18e1497.
Report an issue: GitHub.