gastownhall/beads · error
add federation peer: %w
Error message
add federation peer: %w
What it means
The INSERT ... ON DUPLICATE KEY UPDATE for the federation_peers row failed at the SQL level; the driver error is wrapped as "add federation peer". This indicates a database problem (constraint, connection, schema) rather than a validation problem. Check the wrapped driver error for the root cause.
Source
Thrown at internal/storage/issueops/federation.go:49
// should already be encrypted by the caller; pass nil for no password.
func AddFederationPeerInTx(ctx context.Context, tx *sql.Tx, peer *storage.FederationPeer, encryptedPwd []byte) error {
if err := ValidatePeerName(peer.Name); err != nil {
return fmt.Errorf("invalid peer name: %w", err)
}
_, err := tx.ExecContext(ctx, `
INSERT INTO federation_peers (name, remote_url, username, password_encrypted, sovereignty)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
remote_url = VALUES(remote_url),
username = VALUES(username),
password_encrypted = VALUES(password_encrypted),
sovereignty = VALUES(sovereignty),
updated_at = CURRENT_TIMESTAMP
`, peer.Name, peer.RemoteURL, peer.Username, encryptedPwd, peer.Sovereignty)
if err != nil {
return fmt.Errorf("add federation peer: %w", err)
}
return nil
}
// FederationPeerRow holds raw database fields for a federation peer.
// The caller is responsible for decrypting EncryptedPwd.
type FederationPeerRow struct {
Peer storage.FederationPeer
EncryptedPwd []byte
}
// GetFederationPeerInTx retrieves a federation peer by name.
// Returns storage.ErrNotFound (wrapped) if the peer does not exist.
func GetFederationPeerInTx(ctx context.Context, tx *sql.Tx, name string) (*FederationPeerRow, error) {
var row FederationPeerRow
var lastSync sql.NullTime
var username sql.NullString
View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped driver error to identify the root cause (missing table, deadlock, connection refused)
- Run pending schema migrations so federation_peers exists with the expected columns
- Retry the transaction if the error was transient (connection reset, deadlock)
- Ensure the transaction is still open and not already aborted/rolled back
Example fix
// before
err := issueops.AddFederationPeerInTx(ctx, tx, peer, pwd) // fails: unknown table federation_peers
// after
if err := migrate(ctx, db); err != nil { // ensure schema up to date
return err
}
tx, _ := db.BeginTx(ctx, nil)
err := issueops.AddFederationPeerInTx(ctx, tx, peer, pwd) Defensive patterns
Strategy: try-catch
Validate before calling
// ensure schema is current before writing
if err := migrate(ctx, db); err != nil {
return err
} Try / catch
err := issueops.AddFederationPeerInTx(ctx, tx, peer, pwd)
if err != nil {
var driverErr *mysqldriver.MySQLError
if errors.As(err, &driverErr) {
log.Printf("upsert peer %s failed: code=%d msg=%s", peer.Name, driverErr.Number, driverErr.Message)
}
return fmt.Errorf("add federation peer %s: %w", peer.Name, err)
} Prevention
- Run migrations before any federation write
- Keep transactions short and open them just before the call
- Use errors.As to surface driver error codes for retry decisions
When it happens
Trigger: tx.ExecContext on the federation_peers upsert returns a driver error: table missing, schema mismatch, connection dropped, or constraint violation not caught by name validation.
Common situations: Running against an old database where the federation_peers table doesn't exist yet (needs migration); connection to the Dolt server dropped mid-transaction; another process dropped/locked the table.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- failed to add federation peer: %w
- get federation peer: %w
- list federation peers: %w
- remove federation peer: %w
- failed to begin transaction: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bacf944941a047cd.
Report an issue: GitHub.