{"record":{"id":"6b41ddf3363be645","repo":"gastownhall/beads","slug":"failed-to-encrypt-password-w","errorCode":null,"errorMessage":"failed to encrypt password: %w","messagePattern":"failed to encrypt password: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/credentials.go","lineNumber":287,"sourceCode":"\t})\n}\n\nfunc (s *DoltStore) addFederationPeer(ctx context.Context, peer *storage.FederationPeer) error {\n\t// Validate peer name\n\tif err := validatePeerName(peer.Name); err != nil {\n\t\treturn fmt.Errorf(\"invalid peer name: %w\", err)\n\t}\n\n\t// Encrypt password before storing\n\tvar encryptedPwd []byte\n\tvar err error\n\tif peer.Password != \"\" {\n\t\tif err := s.ensureCredentialKey(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize credential key: %w\", err)\n\t\t}\n\t\tencryptedPwd, err = s.encryptPassword(peer.Password)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to encrypt password: %w\", err)\n\t\t}\n\t}\n\n\t// Upsert the peer credentials\n\t_, err = s.execContext(ctx, `\n\t\tINSERT INTO federation_peers (name, remote_url, username, password_encrypted, sovereignty)\n\t\tVALUES (?, ?, ?, ?, ?)\n\t\tON DUPLICATE KEY UPDATE\n\t\t\tremote_url = VALUES(remote_url),\n\t\t\tusername = VALUES(username),\n\t\t\tpassword_encrypted = VALUES(password_encrypted),\n\t\t\tsovereignty = VALUES(sovereignty),\n\t\t\tupdated_at = CURRENT_TIMESTAMP\n\t`, peer.Name, peer.RemoteURL, peer.Username, encryptedPwd, peer.Sovereignty)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to add federation peer: %w\", err)\n\t}","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/credentials.go#L269-L305","documentation":"After ensuring the credential key exists, addFederationPeer encrypts the peer's password with AES-GCM via encryptPassword; this wraps any failure from that encryption. Encryption itself only fails if the in-memory key is missing (should not happen after ensureCredentialKey) or the crypto primitives/nonce generation fail.","triggerScenarios":"Calling AddFederationPeer with a non-empty peer.Password when encryptWithKey fails — AES cipher/GCM construction error or crypto/rand nonce read failure — or when the key was concurrently reset to nil between ensureCredentialKey and encryptPassword.","commonSituations":"System entropy exhaustion (crypto/rand read failure in constrained containers); key length corruption (key file truncated to non-32 bytes bypassing the 32-byte check upstream); race conditions on a manually constructed store.","solutions":["Retry the operation; transient crypto/rand failures usually indicate entropy starvation — fix the host entropy source (e.g. ensure /dev/urandom availability in the container).","Verify the key file is exactly 32 bytes; a corrupt key file means re-initialization is needed (re-add peer credentials afterwards).","Avoid constructing DoltStore manually in tests; use the standard constructor and call ensureCredentialKey before encryption."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := store.AddFederationPeer(ctx, peer)\nif err != nil && strings.Contains(err.Error(), \"failed to encrypt password\") {\n    // transient crypto/rand failure — retry once after backoff\n    time.Sleep(100 * time.Millisecond)\n    err = store.AddFederationPeer(ctx, peer)\n}","preventionTips":["Ensure adequate entropy in constrained containers","Keep the 32-byte key file intact; never hand-edit it","Construct stores via the standard constructor to avoid nil-key races"],"tags":["go","encryption","aes-gcm","credentials"],"backgroundTag":"password-encryption-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}