gastownhall/beads · error

scanning dependencies row for migration 0053 id backfill: %w

Error message

scanning dependencies row for migration 0053 id backfill: %w

What it means

This wraps a rows.Scan failure while reading dependencies rows whose id is NULL for deterministic backfill during the migration-0053 repair. Scanning fails when the actual column types/nullability in the database do not match the scan destinations (string + three sql.NullString). It indicates schema drift or corrupted row data rather than a query failure.

Source

Thrown at internal/storage/schema/migration_repairs.go:471

func backfillDependenciesID(ctx context.Context, db DBConn) error {
	rows, err := db.QueryContext(ctx, `
		SELECT issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external
		FROM dependencies
		WHERE id IS NULL
	`)
	if err != nil {
		return fmt.Errorf("reading dependencies rows for migration 0053 id backfill: %w", err)
	}
	type edge struct {
		issueID                                              string
		dependsOnIssueID, dependsOnWispID, dependsOnExternal sql.NullString
	}
	var edges []edge
	for rows.Next() {
		var e edge
		if err := rows.Scan(&e.issueID, &e.dependsOnIssueID, &e.dependsOnWispID, &e.dependsOnExternal); err != nil {
			_ = rows.Close()
			return fmt.Errorf("scanning dependencies row for migration 0053 id backfill: %w", err)
		}
		edges = append(edges, e)
	}
	if err := rows.Err(); err != nil {
		return fmt.Errorf("iterating dependencies rows for migration 0053 id backfill: %w", err)
	}
	_ = rows.Close()

	for _, e := range edges {
		target := firstNonNullString(e.dependsOnIssueID, e.dependsOnWispID, e.dependsOnExternal)
		if target == "" {
			// ck_dep_one_target (0041) should make a targetless row
			// unreachable; if one exists anyway, leave its id NULL here --
			// ensureDependenciesIDPrimaryKey below checks for exactly this
			// and fails loudly with an actionable count instead of letting a
			// blind MODIFY ... NOT NULL hard-fail on it, or silently keying
			// the table while pretending the row doesn't exist.
			continue

View on GitHub (pinned to 71377f2769)

Solutions

  1. Find the offending row: run the same WHERE id IS NULL query manually and inspect NULLs/types
  2. Fix data: backfill or delete rows where issue_id IS NULL before re-running the repair
  3. Align column types with expectations (issue_id NOT NULL VARCHAR/CHAR)
  4. If the driver returns []byte, ensure DSN settings (e.g. interpolateParams/charset) or scan into sql.RawBytes/[]byte

Example fix

// before: string target rejects NULL issue_id
var e edge
rows.Scan(&e.issueID, ...)
// after: tolerate NULLs at the source
var issueID sql.NullString
rows.Scan(&issueID, &e.dependsOnIssueID, &e.dependsOnWispID, &e.dependsOnExternal)
if !issueID.Valid { skip or repair row }
Defensive patterns

Strategy: validation

Validate before calling

// detect NULL or mistyped issue_id rows before running the repair
rows, err := db.QueryContext(ctx, `
  SELECT COUNT(*) FROM dependencies
  WHERE id IS NULL AND (issue_id IS NULL
     OR depends_on_issue_id IS NULL AND depends_on_wisp_id IS NULL AND depends_on_external IS NULL)`)
if err != nil { return err }
var bad int
rows.Scan(&bad)
if bad > 0 {
    return fmt.Errorf("%d dependencies rows need manual repair before id backfill", bad)
}

Try / catch

if err := repairV53RigAndSplitTargets(ctx, db); err != nil {
    if strings.Contains(err.Error(), "scanning dependencies row") {
        // inspect offending rows: NULL issue_id or type drift
        return fmt.Errorf("fix dependencies data (NULL issue_id / wrong column types) then retry: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: backfillDependenciesID executes `SELECT issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external FROM dependencies WHERE id IS NULL` and rows.Scan errors on a row — e.g. issue_id NULL when the scan target is a plain string, or a driver type mismatch (bytes vs string) from an unexpected column type.

Common situations: A partially-applied or hand-edited migration left issue_id nullable with NULL rows; a driver/charset change returning []byte where string is expected; rows inserted by an older schema version with different types.

Related errors


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