gastownhall/beads · error
failed to scan federation peer: %w
Error message
failed to scan federation peer: %w
What it means
ListFederationPeers scans each row into a FederationPeer with a fixed column list (name, remote_url, username, password_encrypted, sovereignty, last_sync, created_at, updated_at). This error means rows.Scan failed — the row's data doesn't match the expected 8-column shape or types. The library throws it to surface schema/driver mismatches during iteration.
Source
Thrown at internal/storage/dolt/credentials.go:382
func (s *DoltStore) ListFederationPeers(ctx context.Context) ([]*storage.FederationPeer, error) {
rows, err := s.queryContext(ctx, `
SELECT name, remote_url, username, password_encrypted, sovereignty, last_sync, created_at, updated_at
FROM federation_peers ORDER BY name
`)
if err != nil {
return nil, fmt.Errorf("failed to list federation peers: %w", err)
}
defer rows.Close()
var peers []*storage.FederationPeer
for rows.Next() {
var peer storage.FederationPeer
var encryptedPwd []byte
var lastSync sql.NullTime
var username sql.NullString
if err := rows.Scan(&peer.Name, &peer.RemoteURL, &username, &encryptedPwd, &peer.Sovereignty, &lastSync, &peer.CreatedAt, &peer.UpdatedAt); err != nil {
return nil, fmt.Errorf("failed to scan federation peer: %w", err)
}
if username.Valid {
peer.Username = username.String
}
if lastSync.Valid {
peer.LastSync = &lastSync.Time
}
// Decrypt password
if len(encryptedPwd) > 0 {
if err := s.ensureCredentialKey(ctx); err != nil {
return nil, fmt.Errorf("failed to initialize credential key: %w", err)
}
peer.Password, err = s.decryptPassword(encryptedPwd)
if err != nil {
return nil, fmt.Errorf("failed to decrypt password: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Run bd's schema migration/init to bring federation_peers to the current shape.
- Compare the table schema (SHOW CREATE TABLE federation_peers) against the 8 columns in the SELECT at credentials.go:366; add missing columns or fix types.
- If rows came from a manual import, re-import through AddFederationPeer instead.
- Check for a version mismatch between the bd binary and the database created by another version; align versions.
Example fix
// before: table missing last_sync column from old schema err := rows.Scan(&peer.Name, &peer.RemoteURL, &username, &encryptedPwd, &peer.Sovereignty, &lastSync, &peer.CreatedAt, &peer.UpdatedAt) // scan error // after: migrate schema so all 8 columns exist with compatible types ALTER TABLE federation_peers ADD COLUMN last_sync DATETIME NULL;
Defensive patterns
Strategy: validation
Validate before calling
// verify expected columns before listing rows, err := db.QueryContext(ctx, "SHOW COLUMNS FROM federation_peers") // count columns; expect 8: name, remote_url, username, password_encrypted, sovereignty, last_sync, created_at, updated_at
Try / catch
peers, err := store.ListFederationPeers(ctx)
var scanErr bool
if err != nil && strings.Contains(err.Error(), "failed to scan federation peer") {
scanErr = true // schema drift — run migrations
} Prevention
- Run schema migrations after upgrading beads
- Never hand-edit or ALTER the federation_peers table
- Import peer rows via AddFederationPeer, not raw SQL inserts
- Use one beads version against a given database
When it happens
Trigger: The federation_peers table has a different column count or order than the SELECT expects (schema drift from a different beads version or manual ALTERs); a NOT-NULL column holds a value incompatible with the destination type; driver type-conversion failure on e.g. created_at.
Common situations: Upgrading or downgrading beads so the table schema no longer matches the compiled queries; a hand-edited or partially migrated Dolt database; restoring rows from an export with reordered columns.
Related errors
- db: ListRemotes: scan: %w
- failed to recompute is_blocked: %w
- %s: %w
- failed to add federation peer: %w
- failed to list federation peers: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/091b98b150ce482e.
Report an issue: GitHub.