micro/go-micro · warning
unknown Level String: '%s', defaulting to InfoLevel
Error message
unknown Level String: '%s', defaulting to InfoLevel
What it means
GetLevel converts a level string (from config/env) into a Level constant by comparing against each level's String(). If the string matches no known level it logs at InfoLevel by default and returns this error describing the unrecognized value.
Source
Thrown at logger/level.go:92
// GetLevel converts a level string into a logger Level value.
// returns an error if the input string does not match known values.
func GetLevel(levelStr string) (Level, error) {
switch levelStr {
case TraceLevel.String():
return TraceLevel, nil
case DebugLevel.String():
return DebugLevel, nil
case InfoLevel.String():
return InfoLevel, nil
case WarnLevel.String():
return WarnLevel, nil
case ErrorLevel.String():
return ErrorLevel, nil
case FatalLevel.String():
return FatalLevel, nil
}
return InfoLevel, fmt.Errorf("unknown Level String: '%s', defaulting to InfoLevel", levelStr)
}
func Info(args ...interface{}) {
DefaultLogger.Log(InfoLevel, args...)
}
func Infof(template string, args ...interface{}) {
DefaultLogger.Logf(InfoLevel, template, args...)
}
func Trace(args ...interface{}) {
DefaultLogger.Log(TraceLevel, args...)
}
func Tracef(template string, args ...interface{}) {
DefaultLogger.Logf(TraceLevel, template, args...)
}
View on GitHub (pinned to 24529f1404)
Solutions
- Fix the level string in the config/env to an exact supported value: debug, info, warn, error, or fatal.
- Trim whitespace and normalize case before calling GetLevel.
- Treat the returned error in the caller: either abort startup or accept the InfoLevel default explicitly.
- If you need custom levels, extend the switch/parse logic rather than passing unsupported strings.
Example fix
// before
logger.SetLevel(logger.GetLevel(os.Getenv("LOG_LEVEL")))
// after
lvl, err := logger.GetLevel(strings.TrimSpace(strings.ToLower(os.Getenv("LOG_LEVEL"))))
if err != nil {
log.Printf("config warning: %v", err)
}
logger.SetLevel(lvl) Defensive patterns
Strategy: validation
Validate before calling
var validLevels = map[string]bool{"debug": true, "info": true, "warn": true, "warning": true, "error": true, "fatal": true}
func levelIsValid(s string) bool {
return validLevels[strings.ToLower(strings.TrimSpace(s))]
}
raw := strings.TrimSpace(os.Getenv("LOG_LEVEL"))
if raw != "" && !levelIsValid(raw) {
log.Printf("warning: unknown LOG_LEVEL %q, using info", raw)
} Try / catch
lvl, err := logger.GetLevel(cfg.Level)
if err != nil {
log.Printf("log config: %v", err) // library already defaults to InfoLevel
lvl = logger.InfoLevel
}
logger.SetLevel(lvl) Prevention
- Validate level strings against the supported set at config-load time, before logger init.
- Normalize with strings.ToLower and strings.TrimSpace on env/config input.
- Document the accepted level names where the deployment config lives.
- Fail fast at startup for unknown levels if silent InfoLevel fallback is undesirable.
When it happens
Trigger: Calling GetLevel (typically from an init() that reads a config/env variable like LOGGER_LEVEL) with a value that is not trace/debug/info/warn/warning/error/fatal — including typos, wrong casing beyond what String comparison tolerates, or trailing whitespace.
Common situations: Misconfigured environment variable (e.g. LOG_LEVEL=VERBOSE or 'info ' with a trailing space), deployment configs carrying level names from another logging library, or an unset/blank variable reaching the parser.
Related errors
- agent: ResumeStreamAsk requires a checkpoint
- ai model is nil
- no secret key is defined
- Cannot use two forms of the same flag: <name> <ff.Name>
- flags not parsed
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/dff253455c37d9cc.
Report an issue: GitHub.