gastownhall/beads · error
journal: scan derived is_blocked from %s: %w
Error message
journal: scan derived is_blocked from %s: %w
What it means
While iterating the is_blocked snapshot rows, rows.Scan(&id, &blocked) failed; the rowset is closed and the transaction fails. This means a returned row's values could not be scanned into (string, int).
Source
Thrown at internal/storage/issueops/journal.go:240
end = len(target.ids)
}
inClause, args := buildSQLInClause(target.ids[start:end])
//nolint:gosec // table is one of the two hardcoded values above.
rows, err := tx.QueryContext(ctx,
fmt.Sprintf("SELECT id, is_blocked FROM %s WHERE id IN (%s)", target.table, inClause),
args...)
if err != nil {
if optionalBlockedTable(target.table) && isTableNotExistError(err) {
break
}
return nil, fmt.Errorf("journal: snapshot derived is_blocked from %s: %w", target.table, err)
}
for rows.Next() {
var id string
var blocked int
if err := rows.Scan(&id, &blocked); err != nil {
_ = rows.Close()
return nil, fmt.Errorf("journal: scan derived is_blocked from %s: %w", target.table, err)
}
snapshot[blockedJournalKey{table: target.table, id: id}] = blocked != 0
}
if err := rows.Err(); err != nil {
_ = rows.Close()
return nil, fmt.Errorf("journal: iterate derived is_blocked from %s: %w", target.table, err)
}
if err := rows.Close(); err != nil {
return nil, fmt.Errorf("journal: close derived is_blocked from %s: %w", target.table, err)
}
}
}
return snapshot, nil
}
// recordBlockedJournalChanges compares the stable post-maintenance state with
// the captured state and journals only beads whose derived is_blocked value
// actually changed. The emitted update carries the complete post-mutationView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error to identify the column
- Fix the schema: is_blocked must be NOT NULL integer and id NOT NULL string
- Backfill NULL is_blocked values to 0/1
- Add a migration if upgrading across versions
Example fix
// before
var blocked int
if err := rows.Scan(&id, &blocked); err != nil { ... }
// after
var blocked sql.NullInt64
if err := rows.Scan(&id, &blocked); err != nil { ... }
blockedVal := blocked.Int != 0 Defensive patterns
Strategy: try-catch
Validate before calling
// verify column types before journal operations
rows, _ := db.Query("SELECT id, is_blocked FROM deps LIMIT 1")
var id string; var blocked sql.NullInt64
if rows.Next() && rows.Scan(&id, &blocked) != nil { /* schema drift: is_blocked not int */ } Type guard
null
Try / catch
snap, err := captureBlockedJournalSnapshot(ctx, tx)
if err != nil {
log.Printf("blocked snapshot scan failed: %v", err)
return err // abort transaction; fix schema before retry
} Prevention
- Keep is_blocked NOT NULL INT in all blocked-tracking tables
- Backfill NULLs after any schema change
- Add a migration test comparing expected column types
When it happens
Trigger: is_blocked column is NULL (Scan into int fails) or has a non-integer type (e.g. TEXT) after schema drift; id column NULL or type mismatch.
Common situations: Schema changed is_blocked from NOT NULL to nullable or from INT to another type; manual schema edits; data imported from another tool.
Related errors
- journal: snapshot derived is_blocked from %s: %w
- %s: %w
- failed to scan federation peer: %w
- failed to scan dolt_status: %w
- scan dirty config key: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2cb8b9f0b82d4568.
Report an issue: GitHub.