gastownhall/beads · error

get dependent records: scan: %w

Error message

get dependent records: scan: %w

What it means

This error is returned when scanDependentRow fails while iterating rows of dependent dependency records — the row's columns could not be scanned into types.Dependency (id, issue_id, depends_on_id, type, created_at, created_by, metadata, thread_id). It indicates a shape mismatch between the stored row and the Go scan targets, not a query failure.

Source

Thrown at internal/storage/issueops/dependency_queries.go:201

		batch := targetIDs[start:end]
		placeholders := make([]string, len(batch))
		args := make([]any, len(batch))
		for i, id := range batch {
			placeholders[i] = "?"
			args[i] = id
		}
		rows, err := tx.QueryContext(ctx, fmt.Sprintf(
			`SELECT id, issue_id, %s AS depends_on_id, type, created_at, created_by, metadata, thread_id
			 FROM %s WHERE %s ORDER BY %s`,
			DepTargetExpr, depTable, depTargetIn("", strings.Join(placeholders, ",")), DepTargetExpr), args...)
		if err != nil {
			return fmt.Errorf("get dependent records from %s: %w", depTable, err)
		}
		for rows.Next() {
			dep, scanErr := scanDependentRow(rows)
			if scanErr != nil {
				_ = rows.Close()
				return fmt.Errorf("get dependent records: scan: %w", scanErr)
			}
			// De-dup by row id (depid): the wisp copy of a promoted edge carries
			// the same id as the durable copy scanned first, so skip the repeat.
			if seen[dep.ID] {
				continue
			}
			seen[dep.ID] = true
			result[dep.DependsOnID] = append(result[dep.DependsOnID], dep)
		}
		_ = rows.Close()
		if err := rows.Err(); err != nil {
			return fmt.Errorf("get dependent records: rows: %w", err)
		}
	}
	return nil
}

// Target-keyed dependents-read bounds. A raw read has no consumer to apply a

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped sql scan error to identify which column failed.
  2. Inspect the offending row(s) in the dependency table for NULLs or malformed values (especially created_at, issue_id, type).
  3. Repair or delete the malformed rows; ensure columns declared NOT NULL stay that way.
  4. Re-run migrations so the table schema matches the binary's expected shape.
  5. Check for driver/version mismatch between the app and the database server.

Example fix

// before: orphan row with NULL type crashes the whole read
UPDATE dependencies SET type = 'relates-to' WHERE type IS NULL;
// after: enforce at schema level
ALTER TABLE dependencies MODIFY type VARCHAR(64) NOT NULL;
Defensive patterns

Strategy: validation

Validate before calling

// Check for rows that cannot be scanned before reading dependents
rows, err := tx.QueryContext(ctx, "SELECT id, issue_id, type FROM dependencies WHERE issue_id IS NULL OR type IS NULL")
// any returned row means the read will fail; repair it first

Type guard

func depRowScannable(id, issueID, depType sql.NullString, createdAt sql.NullTime) bool {
    return id.Valid && issueID.Valid && depType.Valid && (!createdAt.Valid || !createdAt.Time.IsZero())
}

Try / catch

deps, err := GetDependentRecordsForIssuesInTx(ctx, tx, targetIDs)
var scanErr interface{ Unwrap() error }
if err != nil && strings.Contains(err.Error(), "scan") {
    // identify and repair the malformed dependency row; do not retry blindly
}

Prevention

When it happens

Trigger: A dependency row contains a NULL in a non-nullable scanned column, a created_at value the driver cannot parse into sql.NullTime, a column type change after a schema migration, or extra/missing columns from a divergent table schema.

Common situations: Manual schema edits or hand-imported rows with NULL issue_id/type; restoring a database from a different beads version; driver type coercion differences (e.g. text vs datetime) after switching storage backends.

Related errors


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