netbirdio/netbird · error
invalid anonymize level %q: use %q or %q
Error message
invalid anonymize level %q: use %q or %q
What it means
effectiveAnonymize (client/cmd/root.go:301-310) validates --anonymize-level by a round-trip: anonymize.ParseLevel maps unknown strings to LevelStrict (client/anonymize/anonymize.go:44), so the CLI compares the input (case-insensitively) to the parsed level's String(); a mismatch means the value was not 'default' or 'strict'. Only those two levels exist: LevelDefault redacts public IPs/domains/MACs; LevelStrict additionally redacts internal ranges, peer names, and netbird keys.
Source
Thrown at client/cmd/root.go:307
var CLIBackOffSettings = &backoff.ExponentialBackOff{
InitialInterval: time.Second,
RandomizationFactor: backoff.DefaultRandomizationFactor,
Multiplier: backoff.DefaultMultiplier,
MaxInterval: 10 * time.Second,
MaxElapsedTime: 30 * time.Second,
Stop: backoff.Stop,
Clock: backoff.SystemClock,
}
// effectiveAnonymize resolves the --anonymize and --anonymize-level flags:
// setting a level implies anonymization, and an invalid level is rejected.
func effectiveAnonymize() (bool, anonymize.Level, error) {
if anonymizeLevelFlag == "" {
return anonymizeFlag, anonymize.LevelDefault, nil
}
level := anonymize.ParseLevel(anonymizeLevelFlag)
if !strings.EqualFold(anonymizeLevelFlag, level.String()) {
return false, anonymize.LevelDefault, fmt.Errorf("invalid anonymize level %q: use %q or %q", anonymizeLevelFlag, anonymize.LevelDefault.String(), anonymize.LevelStrict.String())
}
return true, level, nil
}
func getSetupKey() (string, error) {
if setupKeyPath != "" && setupKey == "" {
return getSetupKeyFromFile(setupKeyPath)
}
return setupKey, nil
}
func getSetupKeyFromFile(setupKeyPath string) (string, error) {
data, err := os.ReadFile(setupKeyPath)
if err != nil {
return "", fmt.Errorf("failed to read setup key file: %v", err)
}
return strings.TrimSpace(string(data)), nil
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Use exactly `--anonymize-level default` or `--anonymize-level strict` (case-insensitive)
- If full redaction is wanted, that is 'strict'; if only public IPs/domains/MACs, that is 'default'
- Drop the flag entirely — anonymization then defaults off, or use plain --anonymize (default level)
- Check NB_ANONYMIZE_LEVEL in the environment and correct or unset it
Example fix
# before netbird debug daemon-logs --anonymize-level medium # -> invalid anonymize level "medium": use "default" or "strict" # after netbird debug daemon-logs --anonymize-level strict
Defensive patterns
Strategy: validation
Validate before calling
level := strings.ToLower(strings.TrimSpace(anonymizeLevelFlag))
if level != "" && level != "default" && level != "strict" {
return fmt.Errorf("invalid anonymize level %q: use \"default\" or \"strict\"", anonymizeLevelFlag)
} Type guard
func isValidAnonymizeLevel(s string) bool {
s = strings.ToLower(strings.TrimSpace(s))
return s == "default" || s == "strict"
} Prevention
- Remember there are exactly two levels: default (public IPs/domains/MACs) and strict (adds internal ranges, peer names, keys)
- Validate NB_ANONYMIZE_LEVEL in CI before invoking the CLI
- Trim whitespace when piping values into the flag
When it happens
Trigger: --anonymize-level set to anything except 'default' or 'strict' (e.g. 'medium', 'full', 'high', 'anonymize'); NB_ANONYMIZE_LEVEL env var with a typo; scripts written for another tool's level names; trailing whitespace in the value (flag parsing does not trim).
Common situations: Users assuming a graded scale (low/medium/high); copy-paste from docs of a different product version; env var typo like NB_ANONYMIZE_LVL spelled out elsewhere and set here; CI setting the env globally for unrelated reasons.
Related errors
- duration must not be negative
- cannot specify both --all flag and state name
- setup config: %v
- setup login request: %v
- invalid filter: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/98b532b94eb32aac.
Report an issue: GitHub.