{"record":{"id":"aca14c6e579603c6","repo":"netbirdio/netbird","slug":"failed-to-switch-profile-w","errorCode":null,"errorMessage":"failed to switch profile: %w","messagePattern":"failed to switch profile: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/android/profile_manager.go","lineNumber":154,"sourceCode":"// an unresolvable path degrades to \"\" rather than an error.\nfunc (pm *ProfileManager) profileEmail(id string) string {\n\tconfigPath, err := pm.getProfileConfigPath(id)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn readProfileEmail(configPath)\n}\n\n// SwitchProfile switches to a different profile\nfunc (pm *ProfileManager) SwitchProfile(id string) error {\n\t// Use ServiceManager to stay consistent with ListProfiles\n\t// ServiceManager uses active_profile.json\n\terr := pm.serviceMgr.SetActiveProfileState(&profilemanager.ActiveProfileState{\n\t\tID:       profilemanager.ID(id),\n\t\tUsername: androidUsername,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to switch profile: %w\", err)\n\t}\n\n\tlog.Infof(\"switched to profile: %s\", id)\n\treturn nil\n}\n\n// AddProfile creates a new profile\nfunc (pm *ProfileManager) AddProfile(profileName string) error {\n\t// Use ServiceManager (creates profile in profiles/ directory)\n\tprofile, err := pm.serviceMgr.AddProfile(profileName, androidUsername)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to add profile: %w\", err)\n\t}\n\n\tlog.Infof(\"created new profile: %s\", profile.ID)\n\treturn nil\n}\n","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/android/profile_manager.go#L136-L172","documentation":"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.","triggerScenarios":"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.","commonSituations":"Device storage exhausted, app-private directory permissions disturbed by backup/restore tooling, two components switching profiles concurrently.","solutions":["Free device storage and retry the switch","Ensure configDir is the app-private files dir and writable by the app","Retry once the I/O condition clears; the state file is rewritten wholesale each switch"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm the state directory is writable before offering profile switching\nif f, err := os.Create(filepath.Join(configDir, \".probe\")); err != nil {\n\t// storage problem: surface it instead of failing inside SwitchProfile\n} else { f.Close(); os.Remove(f.Name()) }","typeGuard":null,"tryCatchPattern":"if err := pm.SwitchProfile(id); err != nil {\n\t// I/O failure writing active_profile.json: free space / verify permissions, then retry;\n\t// the previous active state (if any) remains on disk, so the UI stays consistent\n}","preventionTips":["Keep device storage from filling completely","Route all profile switches through one component to avoid concurrent writes","Switch using ids from ListProfiles so the stored state always points at a real profile"],"tags":["android","go","profile","filesystem","io"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}