{"record":{"id":"3caabffa7b02ba69","repo":"netbirdio/netbird","slug":"failed-to-list-profiles-w","errorCode":null,"errorMessage":"failed to list profiles: %w","messagePattern":"failed to list profiles: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/android/profile_manager.go","lineNumber":95,"sourceCode":"\tprofilemanager.ActiveProfileStatePath = filepath.Join(configDir, \"active_profile.json\")\n\n\t// Create ServiceManager with profiles/ subdirectory\n\t// This avoids modifying the global ConfigDirOverride for profile listing\n\tprofilesDir := filepath.Join(configDir, profilesSubdir)\n\tserviceMgr := profilemanager.NewServiceManagerWithProfilesDir(defaultConfigPath, profilesDir)\n\n\treturn &ProfileManager{\n\t\tconfigDir:  configDir,\n\t\tserviceMgr: serviceMgr,\n\t}\n}\n\n// ListProfiles returns all available profiles\nfunc (pm *ProfileManager) ListProfiles() (*ProfileArray, error) {\n\t// Use ServiceManager (looks in profiles/ directory, checks active_profile.json for IsActive)\n\tinternalProfiles, err := pm.serviceMgr.ListProfiles(androidUsername)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list profiles: %w\", err)\n\t}\n\n\t// Convert internal profiles to Android Profile type\n\tvar profiles []*Profile\n\tfor _, p := range internalProfiles {\n\t\tprofiles = append(profiles, &Profile{\n\t\t\tID:       p.ID.String(),\n\t\t\tName:     p.Name,\n\t\t\tEmail:    pm.profileEmail(p.ID.String()),\n\t\t\tIsActive: p.IsActive,\n\t\t})\n\t}\n\n\treturn &ProfileArray{items: profiles}, nil\n}\n\n// GetActiveProfile returns the currently active profile name\nfunc (pm *ProfileManager) GetActiveProfile() (*Profile, error) {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/android/profile_manager.go#L77-L113","documentation":"ListProfiles delegates to the internal ServiceManager, which reads every profile config under configDir/profiles (plus the default profile) and merges the active state. The whole listing aborts on the first failure: an unreadable directory, an I/O error, or any single profile JSON file that cannot be parsed.","triggerScenarios":"ProfileManager.ListProfiles() → serviceMgr.ListProfiles(\"android\") fails when the profiles/ directory cannot be read (permissions, deleted), a profile .json file is corrupt, or a file read errors mid-scan.","commonSituations":"Corrupt config from an interrupted WriteOutConfig (app killed mid-save), configDir pointing at the wrong path, files restored from backup with wrong ownership, app data partially cleared.","solutions":["Verify the configDir passed to NewProfileManager is the app-private files directory","Inspect the JSON files under configDir/profiles and delete or fix any that are truncated or corrupt","Ensure no other process writes the directory concurrently","Call ListProfiles again after cleanup; a removed file is safe — the profile is recreated on next login"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Sanity-check the profiles directory before first use\nif _, err := os.Stat(filepath.Join(configDir, \"profiles\")); err != nil && !os.IsNotExist(err) {\n\t// permissions/I/O problem: fix before calling ListProfiles\n}","typeGuard":null,"tryCatchPattern":"profiles, err := pm.ListProfiles()\nif err != nil {\n\t// fall back: treat as no extra profiles; offer the default profile and a login\n\tprofiles = nil\n}","preventionTips":["Pass the app-private files dir as configDir; never shared storage","Do not hand-edit profile JSON files","Keep writes single-threaded through ProfileManager so files are never partially written","On corrupt-file errors, inspect and prune configDir/profiles rather than retrying blindly"],"tags":["android","go","filesystem","profile","json"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}