uber-go/zap · error

unrecognized level: %q

Error message

unrecognized level: %q

What it means

levelToFunc in global.go maps a zapcore.Level string (via levelToFunc's caller's parsed level) to the corresponding logger method for redirecting std log output. When the supplied level string does not match any known zap level (Debug, Info, Warn, Error, DPanic, Panic, Fatal), it returns this error. It means the level value passed to NewStdLogAt or redirectStdLogAt was not a recognized zap level.

Source

Thrown at global.go:158

func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
	switch lvl {
	case DebugLevel:
		return logger.Debug, nil
	case InfoLevel:
		return logger.Info, nil
	case WarnLevel:
		return logger.Warn, nil
	case ErrorLevel:
		return logger.Error, nil
	case DPanicLevel:
		return logger.DPanic, nil
	case PanicLevel:
		return logger.Panic, nil
	case FatalLevel:
		return logger.Fatal, nil
	}
	return nil, fmt.Errorf("unrecognized level: %q", lvl)
}

type loggerWriter struct {
	logFunc func(msg string, fields ...Field)
}

func (l *loggerWriter) Write(p []byte) (int, error) {
	p = bytes.TrimSpace(p)
	l.logFunc(string(p))
	return len(p), nil
}

View on GitHub (pinned to bbd4ecbd87)

Solutions

  1. Use one of the recognized level strings: debug, info, warn, error, dpanic, panic, fatal.
  2. Normalize user/config input with zapcore.ParseLevel or strings.ToLower before passing to NewStdLogAt/RedirectStdLogAt.
  3. Handle the returned error by falling back to a default level (e.g. InfoLevel) instead of failing startup.

Example fix

// before
logger, err := zap.NewStdLogAt(zapLog, "verbose")
// after
lvl, perr := zapcore.ParseLevel("verbose") // still fails; validate input first
if perr != nil {
    lvl = zapcore.InfoLevel
}
logger, err := zap.NewStdLogAt(zapLog, lvl.String())
Defensive patterns

Strategy: validation

Validate before calling

func validZapLevel(s string) bool {
    switch strings.ToLower(strings.TrimSpace(s)) {
    case "debug", "info", "warn", "error", "dpanic", "panic", "fatal":
        return true
    }
    return false
}

Try / catch

lvl, err := zapcore.ParseLevel(cfg.Level)
if err != nil {
    lvl = zapcore.InfoLevel // fallback
}
stdLog, err := zap.NewStdLogAt(zapLog, lvl)

Prevention

When it happens

Trigger: Calling zap.NewStdLogAt(l, level) or zap.RedirectStdLogAt(l, level) with a level string that is not one of debug/info/warn/error/dpanic/panic/fatal (case variations or typos like 'trace' or 'verbose' are rejected).

Common situations: Level names read from environment variables or config files that use non-zap naming conventions (e.g. 'trace', 'verbose', 'notice', or uppercase 'DEBUG' if parsed case-sensitively by the caller), or typos in programmatic level constants.

Related errors


AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31). Data as JSON: /api/errors/58803efed54eabc7. Report an issue: GitHub.