netbirdio/netbird · error

failed to switch profile: %w

Error message

failed to switch profile: %w

What it means

SwitchProfile persists the new active profile by marshalling ActiveProfileState and writing active_profile.json. The wrapped error comes from that write path — encoding or I/O failure — not from validating the target profile: the id is stored as given and existence of the profile is not checked here.

Source

Thrown at client/android/profile_manager.go:154

// an unresolvable path degrades to "" rather than an error.
func (pm *ProfileManager) profileEmail(id string) string {
	configPath, err := pm.getProfileConfigPath(id)
	if err != nil {
		return ""
	}
	return readProfileEmail(configPath)
}

// SwitchProfile switches to a different profile
func (pm *ProfileManager) SwitchProfile(id string) error {
	// Use ServiceManager to stay consistent with ListProfiles
	// ServiceManager uses active_profile.json
	err := pm.serviceMgr.SetActiveProfileState(&profilemanager.ActiveProfileState{
		ID:       profilemanager.ID(id),
		Username: androidUsername,
	})
	if err != nil {
		return fmt.Errorf("failed to switch profile: %w", err)
	}

	log.Infof("switched to profile: %s", id)
	return nil
}

// AddProfile creates a new profile
func (pm *ProfileManager) AddProfile(profileName string) error {
	// Use ServiceManager (creates profile in profiles/ directory)
	profile, err := pm.serviceMgr.AddProfile(profileName, androidUsername)
	if err != nil {
		return fmt.Errorf("failed to add profile: %w", err)
	}

	log.Infof("created new profile: %s", profile.ID)
	return nil
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Free device storage and retry the switch
  2. Ensure configDir is the app-private files dir and writable by the app
  3. Retry once the I/O condition clears; the state file is rewritten wholesale each switch
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the state directory is writable before offering profile switching
if f, err := os.Create(filepath.Join(configDir, ".probe")); err != nil {
	// storage problem: surface it instead of failing inside SwitchProfile
} else { f.Close(); os.Remove(f.Name()) }

Try / catch

if err := pm.SwitchProfile(id); err != nil {
	// I/O failure writing active_profile.json: free space / verify permissions, then retry;
	// the previous active state (if any) remains on disk, so the UI stays consistent
}

Prevention

When it happens

Trigger: SetActiveProfileState fails when configDir is unwritable, the disk is full, an existing active_profile.json cannot be overwritten, or the state file sits on read-only storage.

Common situations: Device storage exhausted, app-private directory permissions disturbed by backup/restore tooling, two components switching profiles concurrently.

Related errors


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