netbirdio/netbird · warning
unknown log level: %s. Available levels are: panic, fatal, e
Error message
unknown log level: %s. Available levels are: panic, fatal, error, warn, info, debug, trace
What it means
setLogLevel parses the requested level with server.ParseLogLevel, which lowercases the input and maps only panic, fatal, error, warn, info, debug and trace; anything else returns LogLevel_UNKNOWN and this error. The check happens client-side before any RPC, so the daemon was not contacted. Note the mapping is lowercase-insensitive but strictly named — 'warning', 'err', 'verbose', 'none', or an empty string all fail.
Source
Thrown at client/cmd/debug.go:218
return nil
}
func setLogLevel(cmd *cobra.Command, args []string) error {
conn, err := getClient(cmd)
if err != nil {
return err
}
defer func() {
if err := conn.Close(); err != nil {
log.Errorf(errCloseConnection, err)
}
}()
client := proto.NewDaemonServiceClient(conn)
level := server.ParseLogLevel(args[0])
if level == proto.LogLevel_UNKNOWN {
//nolint
return fmt.Errorf("unknown log level: %s. Available levels are: panic, fatal, error, warn, info, debug, trace\n", args[0])
}
_, err = client.SetLogLevel(cmd.Context(), &proto.SetLogLevelRequest{
Level: level,
})
if err != nil {
return fmt.Errorf("failed to set log level: %v", status.Convert(err).Message())
}
cmd.Println("Log level set successfully to", args[0])
return nil
}
func runForDuration(cmd *cobra.Command, args []string) error {
duration, err := time.ParseDuration(args[0])
if err != nil {
return fmt.Errorf("invalid duration format: %v", err)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Use one of the exact names from the message: panic, fatal, error, warn, info, debug, trace (case-insensitive)
- For 'warning' type 'warn'; for 'err' type 'error'; for 'off/all' there is no equivalent — choose trace (most verbose) or a higher level
- Quote the argument exactly once and confirm it is non-empty: netbird debug log-level 'debug'
Example fix
# before netbird debug log-level warning # -> unknown log level: warning. ... # after netbird debug log-level warn
Defensive patterns
Strategy: validation
Validate before calling
// Reuse the daemon's parser so validation matches exactly:
if server.ParseLogLevel(arg) == proto.LogLevel_UNKNOWN {
return fmt.Errorf("unknown log level: %s", arg)
} Type guard
// Go set membership for the accepted vocabulary:
func isValidLogLevel(s string) bool {
switch strings.ToLower(s) {
case "panic", "fatal", "error", "warn", "info", "debug", "trace":
return true
}
return false
} Prevention
- Normalize level names in scripts to the seven accepted words before passing them
- Map other vocabularies up front: warning->warn, err->error, off/all have no equivalent
- Validate config-stored level strings at config load time, not at command time
When it happens
Trigger: netbird debug log-level warning (the canonical name is warn); netbird debug log-level err or ERROR_LEVEL; passing a logrus/zap level name that is not in the list (trace is supported, 'fatal' is, 'panic' is, but 'all'/'off' are not); quoting issues leaving an empty argument.
Common situations: Users assuming the log levels of the underlying logging library carry over (logrus uses warn but people type warning; some tools use notice/emerg); scripts parameterized from a config that stores a different level vocabulary; muscle memory from netbird up --log-level? — the accepted set is identical, but typos still trip it.
Related errors
- failed initializing log %v
- invalid filter: %w
- duration must not be negative
- failed to set log level: %v
- invalid duration format: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/a0f77210e82b46c7.
Report an issue: GitHub.