gastownhall/beads · error

failed to iterate peers for migration: %w

Error message

failed to iterate peers for migration: %w

What it means

After scanning all federation_peers rows, migrateCredentialKeys checks rows.Err() to detect any error that terminated row iteration. This error wraps such an iteration failure — typically a dropped or timed-out database connection mid-scan, or a driver-level read error. It guarantees a broken migration is reported instead of silently re-encrypting only a prefix of the peer list.

Source

Thrown at internal/storage/dolt/credentials.go:178

	var toMigrate []migrationEntry
	for rows.Next() {
		var name string
		var encrypted []byte
		if err := rows.Scan(&name, &encrypted); err != nil {
			return fmt.Errorf("failed to scan peer for migration: %w", err)
		}

		// Decrypt with old key
		plaintext, err := decryptWithKey(encrypted, oldKey)
		if err != nil {
			// Can't decrypt with old key — skip (may already use a different scheme)
			continue
		}
		toMigrate = append(toMigrate, migrationEntry{name: name, plaintext: plaintext})
	}
	if err := rows.Err(); err != nil {
		return fmt.Errorf("failed to iterate peers for migration: %w", err)
	}

	// Re-encrypt each password with the new key
	for _, entry := range toMigrate {
		encrypted, err := encryptWithKey(entry.plaintext, newKey)
		if err != nil {
			return fmt.Errorf("failed to re-encrypt password for peer %s: %w", entry.name, err)
		}
		if _, err := s.execContext(ctx, `
			UPDATE federation_peers SET password_encrypted = ? WHERE name = ?
		`, encrypted, entry.name); err != nil {
			return fmt.Errorf("failed to update encrypted password for peer %s: %w", entry.name, err)
		}
	}

	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Increase the context/command timeout or retry — migration re-runs on next open while no key file exists
  2. Verify connectivity to the Dolt server (ping/hosted instance health) and network stability
  3. Check server logs for aborted connections around the failure time
  4. Reduce peer-table contention: ensure no concurrent bd processes hold long transactions on federation_peers
Defensive patterns

Strategy: retry

Validate before calling

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() // give row iteration room to finish on slow links

Try / catch

if err := bdSync(); err != nil && strings.Contains(err.Error(), "failed to iterate peers for migration") {
    return retryWithBackoff(bdSync, 3) // migration re-runs safely while no key file exists
}

Prevention

When it happens

Trigger: rows.Err() returns non-nil after the rows.Next() loop in migrateCredentialKeys: the SQL connection to Dolt dropped or the context was canceled/timed out while streaming rows, or the underlying driver hit an I/O error reading the result set.

Common situations: Slow or flaky connection to a remote dolt-sql-server timing out during migration on open; context deadline exceeded because migration ran during a slow startup with many peers; network interruption to a hosted Dolt instance.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/8cb7ff8168d7b952. Report an issue: GitHub.