gastownhall/beads · error
scan dependent: %w
Error message
scan dependent: %w
What it means
This is the lowest-level decode error in dependency_queries.go: scanDependentRow failed to Scan a dependency row's eight columns into a types.Dependency struct (with sql.NullTime/NullString for nullable fields). All higher-level dependent-record and count errors funnel through it, so it always indicates a row-content or schema-shape problem, not a connection problem.
Source
Thrown at internal/storage/issueops/dependency_queries.go:341
if scanErr != nil {
return nil, fmt.Errorf("get dependent records: scan: %w", scanErr)
}
deps = append(deps, dep)
}
return deps, rows.Err()
}
// scanDependentRow scans a dependents row that INCLUDES the row id (the keyset
// cursor). The shared scanDependencyRow does not select id, and adding it there
// would ripple through every source-keyed read, so the target-keyed read owns
// this variant.
func scanDependentRow(rows *sql.Rows) (*types.Dependency, error) {
var dep types.Dependency
var createdAt sql.NullTime
var metadata, threadID sql.NullString
if err := rows.Scan(&dep.ID, &dep.IssueID, &dep.DependsOnID, &dep.Type, &createdAt, &dep.CreatedBy, &metadata, &threadID); err != nil {
return nil, fmt.Errorf("scan dependent: %w", err)
}
if createdAt.Valid {
dep.CreatedAt = createdAt.Time
}
if metadata.Valid {
dep.Metadata = metadata.String
}
if threadID.Valid {
dep.ThreadID = threadID.String
}
return &dep, nil
}
// CountDependentRecordsInTx returns the number of DISTINCT inbound edges of
// targetID, applying the same sargable target predicate and optional depType
// filter as GetDependentRecordsInTx but no keyset/limit. Callers that want a
// true total membership count need it without paging to exhaustion. Like the
// paged read it is a RAW count spanning both tables; the caller applies anyView on GitHub (pinned to 71377f2769)
Solutions
- Parse the wrapped error: it names the column/conversion that failed (e.g. 'converting NULL to string is unsupported').
- Locate the bad row by id prefix of the failing table and repair or delete it.
- Re-run or hand-apply pending migrations to match expected schema (id, issue_id, depends_on columns, type, created_at, created_by, metadata, thread_id).
- If corruption is suspected, restore from backup or re-init the database.
- Keep nullable columns in scans as sql.Null* when the schema permits NULL.
Example fix
// before: schema missing thread_id column after partial migration SELECT id, issue_id, issue_id AS depends_on_id, type, created_at, created_by, metadata FROM dependencies; // after: complete migration adds the column ALTER TABLE dependencies ADD COLUMN thread_id VARCHAR(64) NULL;
Defensive patterns
Strategy: validation
Validate before calling
// Verify the table shape matches the scanner's expectation (8 columns, right names)
cols, _ := tx.QueryContext(ctx, "SELECT * FROM dependencies LIMIT 1")
ts, _ := cols.ColumnTypes()
// expect: id, issue_id, depends_on target column(s), type, created_at, created_by, metadata, thread_id
if len(ts) < 8 { /* migration incomplete; repair before reading */ } Type guard
func scanDependentSafe(rows *sql.Rows) (dep *types.Dependency, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("scan dependent: %v", r) } }()
return scanDependentRow(rows)
} Try / catch
dep, err := scanDependentRow(rows)
if err != nil {
// unwrap to find failing column: errors.Is/As on the driver error, then repair schema/data
log.Printf("bad dependency row in %s: %v", table, err)
} Prevention
- Treat partial migrations as an alert condition; verify column set post-migration
- Keep nullable columns nullable in scans (sql.NullString/NullTime)
- Never alter dependency table schemas by hand
- Run integration tests that round-trip a dependency edge through both tables
When it happens
Trigger: Any read path (GetDependentRecordsForIssuesInTx, GetDependentRecordsInTx) encountering a row whose column count or types don't match: NULL issue_id/depends_on_id/type/id, non-time created_at, schema with missing or reordered columns.
Common situations: Partial migrations leaving tables with old column sets; manual data fixes that NULLed required columns; database restored from an incompatible version; corrupted storage files.
Related errors
- get dependent records: scan: %w
- ErrExec
- database not available: %w
- no database connection
- GetIssuesByIDs: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e7987ddd99e67c5a.
Report an issue: GitHub.