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

  1. Locate and repair the offending row (NULL issue_id or NULL target in the named dependency table)
  2. Check whether DepTargetExpr was modified and still returns a plain string
  3. Confirm the dependency tables were not written by an incompatible schema version
  4. 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

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


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