netbirdio/netbird · error
id '%s' is not valid
Error message
id '%s' is not valid
What it means
LogoutProfile re-validates the profile id with IsValidProfileFilenameStem and rejects ids that are empty, longer than 64 characters, contain '/', '\', '..', or any character outside letters/digits/underscore/hyphen — a path-traversal guard before the config path is used. Note that in the current code this exact check is shadowed: getProfileConfigPath runs the same validation first (line 175), so an invalid id normally surfaces earlier as 'id %q is not valid'.
Source
Thrown at client/android/profile_manager.go:181
// 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
}
// LogoutProfile logs out from a profile (clears authentication)
func (pm *ProfileManager) LogoutProfile(id string) error {
configPath, err := pm.getProfileConfigPath(id)
if err != nil {
return err
}
if !profilemanager.IsValidProfileFilenameStem(profilemanager.ID(id)) {
return fmt.Errorf("id '%s' is not valid", id)
}
// Check if profile exists
if _, err := os.Stat(configPath); os.IsNotExist(err) {
return fmt.Errorf("profile '%s' does not exist", id)
}
// Read current config using internal profilemanager
config, err := profilemanager.ReadConfig(configPath)
if err != nil {
return fmt.Errorf("failed to read profile config: %w", err)
}
// Clear authentication by removing private key and SSH key
config.PrivateKey = ""
config.SSHKey = ""
// Save config using internal profilemanagerView on GitHub (pinned to 93e97f4bf1)
Solutions
- Pass only ids obtained from ListProfiles or GetActiveProfile
- Use "default" for the default profile
- Reject path-like free-form input in the UI layer before calling
Example fix
// before pm.LogoutProfile(profile.Name) // display name; may contain dots/spaces → rejected // after pm.LogoutProfile(profile.ID) // stem-safe id exactly as returned by ListProfiles
Defensive patterns
Strategy: validation
Validate before calling
// Reject non-stem ids before calling LogoutProfile (mirrors IsValidProfileFilenameStem)
if !isValidProfileID(id) {
// do not call; ids must come from ListProfiles/GetActiveProfile
} Type guard
func isValidProfileID(id string) bool {
if id == "" || len(id) > 64 {
return false
}
if strings.ContainsAny(id, `/") || strings.Contains(id, "..") {
return false
}
if filepath.Base(id) != id {
return false
}
for _, r := range id {
if !(unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-') {
return false
}
}
return true
} Try / catch
if err := pm.LogoutProfile(id); err != nil {
if strings.Contains(err.Error(), "is not valid") {
// caller bug: a display name or path was passed instead of a profile ID
} else if strings.Contains(err.Error(), "does not exist") {
// stale entry; refresh the list
}
} Prevention
- Never derive ids from user input; use ListProfiles/GetActiveProfile values
- Use "default" for the default profile
- Remember dot is not a legal stem character — filenames like work.json must be passed as work
When it happens
Trigger: LogoutProfile called with a display name, a filename like "work.json" (the dot is not a legal stem character), or any path-like/free-form string instead of the raw ID returned by ListProfiles.
Common situations: Java/Kotlin UI passing the profile Name field instead of ID, hardcoded ids containing dots or spaces, ids from an older app version that predated sanitization.
Related errors
- id %q is not valid
- failed to add profile: %w
- failed to rename profile: %w
- failed to list profiles: %w
- failed to get active profile: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/8fc70a75d18d2e10.
Report an issue: GitHub.