netbirdio/netbird · error
failed to remove profile: %w
Error message
failed to remove profile: %w
What it means
RemoveProfile deletes the profile through ServiceManager.RemoveProfile from profiles/. It fails when the id is not a valid filename stem, the profile file cannot be removed (I/O error), or related internal steps fail. The subsequent removal of the stored account email is deliberately best-effort and only logged, never returned, so this error always concerns the profile deletion itself.
Source
Thrown at client/android/profile_manager.go:233
func (pm *ProfileManager) RenameProfile(id string, newName string) error {
if err := pm.serviceMgr.RenameProfile(profilemanager.ID(id), androidUsername, newName); err != nil {
return fmt.Errorf("failed to rename profile: %w", err)
}
log.Infof("renamed profile %s to: %s", id, newName)
return nil
}
// RemoveProfile deletes a profile
func (pm *ProfileManager) RemoveProfile(id string) error {
configPath, err := pm.getProfileConfigPath(id)
if err != nil {
return err
}
// Use ServiceManager (removes profile from profiles/ directory)
if err := pm.serviceMgr.RemoveProfile(profilemanager.ID(id), androidUsername); err != nil {
return fmt.Errorf("failed to remove profile: %w", err)
}
// The account file is this package's, not the ServiceManager's, so it must
// go here. The default profile has a fixed filename, so a recreated one
// would otherwise inherit the deleted profile's email as its login_hint.
// Not fatal: the profile itself is gone.
if err := removeProfileEmail(configPath); err != nil {
log.Warnf("failed to remove stored account email for profile %s: %v", id, err)
}
log.Infof("removed profile: %s", id)
return nil
}
// getProfileConfigPath returns the config file path for a profile
// This is needed for Android-specific path handling (netbird.cfg for default profile)
func (pm *ProfileManager) getProfileConfigPath(id string) (string, error) {
if !profilemanager.IsValidProfileFilenameStem(profilemanager.ID(id)) {View on GitHub (pinned to 93e97f4bf1)
Solutions
- Refresh ListProfiles and remove by a current id
- Treat a repeat removal of an already-gone profile as success in the UI
- Retry on transient I/O errors after checking storage
Example fix
// before: every tap fires a removal
removeBtn.setOnClickListener { pm.RemoveProfile(id) }
// after: ignore the error when the profile is already gone
if err := pm.RemoveProfile(id); err != nil {
if !profileStillExists(pm, id) { /* already removed: treat as success */ }
} Defensive patterns
Strategy: validation
Validate before calling
// Refresh and confirm the profile still exists before removing
list, err := pm.ListProfiles()
if err == nil && !containsId(list, id) {
// nothing to remove; skip the call
} Try / catch
if err := pm.RemoveProfile(id); err != nil {
list, lerr := pm.ListProfiles()
if lerr == nil && !containsId(list, id) {
// already gone: treat as success
} else {
// real removal failure: retry after checking storage
}
} Prevention
- Disable the remove action for an entry once it succeeds
- Always remove through ProfileManager so the state file stays consistent
- Remember the default profile's config lives at configDir/netbird.cfg, not under profiles/
When it happens
Trigger: RemoveProfile with an invalid id, a profile whose file is locked or unreadable, or an id already removed (repeat removal). The default profile, whose config lives at configDir/netbird.cfg rather than under profiles/, is not managed by this directory path.
Common situations: Double-tap on remove where the second call finds nothing, stale list entry after files changed externally, file locked by a concurrent read.
Related errors
- failed to list profiles: %w
- failed to get active profile: %w
- failed to resolve active profile %q: %w
- failed to switch profile: %w
- profile '%s' does not exist
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/8eb26948e5edf0c3.
Report an issue: GitHub.