gastownhall/beads · error
failed to scan history: %w
Error message
failed to scan history: %w
What it means
After the history query succeeds, getIssueHistory scans each row into the issue and history structs, including nullable TEXT columns read as sql.Null* values. This error is returned when rows.Scan fails — almost always a column-count or column-type mismatch between the SELECT * projection and the fixed scan target list, or an unparseable value in a scanned column.
Source
Thrown at internal/storage/dolt/history.go:108
var history []*issueHistory
for rows.Next() {
var h issueHistory
var issue types.Issue
var createdAtStr, updatedAtStr sql.NullString // TEXT columns - must parse manually
var closedAt sql.NullTime
var assignee, owner, createdBy, closeReason, molType sql.NullString
var estimatedMinutes sql.NullInt64
var pinned sql.NullInt64
if err := rows.Scan(
&issue.ID, &issue.Title, &issue.Description, &issue.Design, &issue.AcceptanceCriteria, &issue.Notes,
&issue.Status, &issue.Priority, &issue.IssueType, &assignee, &owner, &createdBy,
&estimatedMinutes, &createdAtStr, &updatedAtStr, &closedAt, &closeReason,
&pinned, &molType,
&h.CommitHash, &h.Committer, &h.CommitDate,
); err != nil {
return nil, fmt.Errorf("failed to scan history: %w", err)
}
// Parse timestamp strings (TEXT columns require manual parsing)
if createdAtStr.Valid {
issue.CreatedAt = parseTimeString(createdAtStr.String)
}
if updatedAtStr.Valid {
issue.UpdatedAt = parseTimeString(updatedAtStr.String)
}
if closedAt.Valid {
issue.ClosedAt = &closedAt.Time
}
if assignee.Valid {
issue.Assignee = assignee.String
}
if owner.Valid {
issue.Owner = owner.StringView on GitHub (pinned to 71377f2769)
Solutions
- Align the beads binary and database schema versions — run the project's schema migration/upgrade steps so dolt_history_issues matches the compiled scan list.
- Check the wrapped error message: it names the offending column/index; compare current SHOW CREATE TABLE dolt_history_issues output with the Scan target order.
- Upgrade or downgrade the Dolt engine to a version compatible with the installed beads release.
Example fix
// before rows, _ := s.queryContext(ctx, "SELECT * FROM dolt_history_issues ...") // column drift rows.Scan(&issue.ID, ..., &h.CommitDate) // scan count mismatch // after rows, _ := s.queryContext(ctx, "SELECT id, title, description, ... commit_hash, committer, commit_date FROM dolt_history_issues ...") // explicit column list rows.Scan(&issue.ID, ..., &h.CommitDate)
Defensive patterns
Strategy: try-catch
Validate before calling
func schemaMatches(db *sql.DB) error {
rows, err := db.Query("SHOW COLUMNS FROM dolt_history_issues")
if err != nil { return err }
defer rows.Close()
return nil // compare count/names against expected scan list in production
} Try / catch
history, err := store.GetIssueHistory(ctx, id)
if err != nil && strings.Contains(err.Error(), "failed to scan history") {
return fmt.Errorf("beads/schema version mismatch, run migrations: %w", err)
} Prevention
- Keep beads binary and database schema versions in lockstep; run migrations on upgrade.
- Prefer explicit column lists over SELECT * when scanning into fixed structs.
- Pin the Dolt engine version per beads release in deployment configs.
When it happens
Trigger: The dolt_history_issues schema drifts from the code's expectation (added/removed/reordered columns) so SELECT * returns a different column set than the Scan targets; a column type changes (e.g. a numeric returned as string); NULL appears where a non-Null scan target is used.
Common situations: Upgrading the Dolt server which changes system-table schema; beads schema migrations applied to the DB but binary not updated (or vice versa); running a mixed-version fleet where one node wrote rows with new columns.
Related errors
- failed to scan conflict: %w
- ErrScan
- failed to get issue history: %w
- failed to get issue history: %w
- compact step %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/aa878136679678c4.
Report an issue: GitHub.