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

  1. Fix the level string in the config/env to an exact supported value: debug, info, warn, error, or fatal.
  2. Trim whitespace and normalize case before calling GetLevel.
  3. Treat the returned error in the caller: either abort startup or accept the InfoLevel default explicitly.
  4. 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

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


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/dff253455c37d9cc. Report an issue: GitHub.