gastownhall/beads · error
failed to re-encrypt password for peer %s: %w
Error message
failed to re-encrypt password for peer %s: %w
What it means
When re-encrypting a peer password during migration, migrateCredentialKeys calls encryptWithKey(plaintext, newKey) with the freshly generated key. This error wraps an encryption failure for the named peer. Since the new key is always a valid 32-byte AES-256 key, this fails only when the nonce read from crypto/rand fails or the crypto setup errors — rare, but aborting is required to avoid storing a password encrypted in an unusable way.
Source
Thrown at internal/storage/dolt/credentials.go:185
}
// 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
}
// encryptWithKey encrypts plaintext using AES-GCM with the given key.
func encryptWithKey(plaintext string, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)View on GitHub (pinned to 71377f2769)
Solutions
- Retry the operation — nonce-generation failures from crypto/rand are almost always transient
- If it persists, fix the OS entropy source (check /dev/urandom, getrandom availability, container policies)
- Restore the peer's plaintext password and re-add the peer (`bd` peer add) if migration left it un-migrated; the old ciphertext remains intact since the UPDATE never ran
Defensive patterns
Strategy: retry
Try / catch
if err := bdCmd(); err != nil && strings.Contains(err.Error(), "failed to re-encrypt password for peer") {
return retryWithBackoff(bdCmd, 2) // entropy failures are transient
} Prevention
- Ensure a healthy entropy source in production containers
- Always let bd generate keys (never inject custom-length keys)
- Keep peer credentials documented so they can be re-entered if migration aborts
When it happens
Trigger: encryptWithKey fails while migrating a stored peer password: io.ReadFull(rand.Reader, nonce) errors (entropy source failure) inside encryptWithKey, or aes.NewCipher/cipher.NewGCM error (only if the new key were not 32 bytes, which cannot happen from the normal generation path).
Common situations: Entropy exhaustion or a broken CSPRNG in a container at boot (same root cause as key-generation failure); custom code paths or tests supplying a wrong-length key; crypto misconfiguration in exotic environments.
Related errors
- failed to migrate credential keys: %w
- ciphertext too short
- failed to encrypt password: %w
- failed to decrypt password: %w
- clone from %s succeeded, but the database needs %d schema %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/865dc40d1049eac1.
Report an issue: GitHub.