netbirdio/netbird · error

failed to rename profile: %w

Error message

failed to rename profile: %w

What it means

RenameProfile delegates to ServiceManager.RenameProfile, which validates both the id (filename-stem rules) and the new display name (non-empty after sanitization, valid UTF-8, at most 128 runes), then rewrites only the "name" field of the profile config — the id and on-disk filename stay fixed. The error wraps a validation failure or the config read/write I/O.

Source

Thrown at client/android/profile_manager.go:217

	// Save config using internal profilemanager
	if err := profilemanager.WriteOutConfig(configPath, config); err != nil {
		return fmt.Errorf("failed to save config: %w", err)
	}

	// The stored account email is kept on purpose, matching the desktop and CLI
	// logout semantics: the next login passes it as the login_hint so the IdP
	// preselects the account. Removing the profile is what deletes it.
	log.Infof("logged out from profile: %s", id)
	return nil
}

// RenameProfile changes a profile's display name. The profile ID, and therefore
// its on-disk filename, is left untouched: only the "name" field of the config
// is rewritten. This works for the default profile too, whose config lives in
// netbird.cfg rather than under profiles/.
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)
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Use the id from ListProfiles, never the display name
  2. Trim the new name and cap it at 128 characters
  3. If both are valid, check storage health and retry

Example fix

// before
pm.RenameProfile(profile.Name, newName)

// after
pm.RenameProfile(profile.ID, strings.TrimSpace(newName))
Defensive patterns

Strategy: validation

Validate before calling

newName = strings.TrimSpace(newName)
if newName == "" || utf8.RuneCountInString(newName) > 128 || !isValidProfileID(id) {
	// reject in the UI before calling RenameProfile
}

Type guard

func validRename(id, name string) bool {
	return isValidProfileID(id) && utf8.RuneCountInString(strings.TrimSpace(name)) <= 128 && strings.TrimSpace(name) != ""
}

Try / catch

if err := pm.RenameProfile(id, newName); err != nil {
	if !validRename(id, newName) {
		// input problem: fix id (use ListProfiles value) or name
	} else {
		// I/O problem: check storage and retry
	}
}

Prevention

When it happens

Trigger: RenameProfile with a display name or path-like string as the id, a new name that is empty after trimming or longer than 128 characters, or a profile config file that is missing/unwritable at save time.

Common situations: UI sending the Name field as the id, a blank new name from an empty dialog, storage issues at the moment of the rewrite.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/8615cb3637ea9295. Report an issue: GitHub.