gastownhall/beads · error
scan child status: %w
Error message
scan child status: %w
What it means
Rows from the child-status batch query are scanned into two strings (id, status). A Scan mismatch aborts with this error. It means a child row's id or status could not be read as a string, so the child-status map would be incomplete and closure evaluation is halted.
Source
Thrown at internal/storage/issueops/epic_closure.go:98
if end > len(allChildIDs) {
end = len(allChildIDs)
}
batch := allChildIDs[start:end]
placeholders, args := buildSQLInClause(batch)
statusQuery := fmt.Sprintf("SELECT id, status FROM %s WHERE id IN (%s)", table, placeholders)
statusRows, err := tx.QueryContext(ctx, statusQuery, args...)
if err != nil {
if isTableNotExistError(err) {
break // wisps table may not exist on pre-migration databases
}
return nil, fmt.Errorf("failed to batch-fetch child statuses from %s: %w", table, err)
}
for statusRows.Next() {
var id, status string
if err := statusRows.Scan(&id, &status); err != nil {
statusRows.Close()
return nil, fmt.Errorf("scan child status: %w", err)
}
childStatusMap[id] = status
}
statusRows.Close()
}
}
}
// Step 4: Batch-fetch all epic issues
epicsWithChildren := make([]string, 0)
for _, epicID := range epicIDs {
if len(epicChildMap[epicID]) > 0 {
epicsWithChildren = append(epicsWithChildren, epicID)
}
}
epicIssues, err := GetIssuesByIDsInTx(ctx, tx, epicsWithChildren, nil)
if err != nil {
return nil, fmt.Errorf("failed to batch-fetch epic issues: %w", err)View on GitHub (pinned to 71377f2769)
Solutions
- Locate rows with NULL/invalid status in the named table and set them to a valid status.
- Align the schema with the current bd migrations.
- Remove corrupt rows and re-sync from the primary database.
- Retry the closure command after repair.
Example fix
// before UPDATE issues SET status = NULL WHERE id = 'bd-1'; // after UPDATE issues SET status = 'open' WHERE id = 'bd-1';
Defensive patterns
Strategy: validation
Validate before calling
rows, _ := db.Query("SELECT id, status FROM issues WHERE id IN (?)", ids)
for rows.Next() {
var id, status sql.NullString
_ = rows.Scan(&id, &status)
if !id.Valid || !status.Valid { return fmt.Errorf("child %v has NULL status", id) }
} Type guard
func isChildStatusScanErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "scan child status:")
} Try / catch
epics, err := GetEpicsEligibleForClosureInTx(ctx, tx)
if err != nil {
if isChildStatusScanErr(err) { return backfillStatusesThenRetry(ctx) }
return err
} Prevention
- Backfill NULL statuses to a valid default after schema changes.
- Validate statuses against bd's allowed values on import.
- Avoid external writers to issues/wisps tables.
- Run integrity checks after restores.
When it happens
Trigger: Calling GetEpicsEligibleForClosureInTx when a status row contains a NULL or non-string id/status value that the driver cannot convert.
Common situations: Rows with NULL status inserted by other tooling; enum/typed status columns in a divergent schema; corrupted wisps/issues rows.
Related errors
- scan epic id: %w
- scan parent-child dep from %s: %w
- failed to scan dolt_status: %w
- scan dirty config key: %w
- db: ChildCounterSQLRepository.NextChildID: scan: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f651bdb3c2da2de3.
Report an issue: GitHub.