caddyserver/caddy · error

unrecognized log level: %s

Error message

unrecognized log level: %s

What it means

After placeholder replacement and lowercasing, the level string did not match any of Caddy's accepted levels: debug, info (or empty), warn, error, panic, fatal. This is a plain bad-value error, not a placeholder-resolution error.

Source

Thrown at logging.go:774

	}
	level = strings.ToLower(level)

	// set up the log level
	switch level {
	case "debug":
		return zapcore.DebugLevel, nil
	case "", "info":
		return zapcore.InfoLevel, nil
	case "warn":
		return zapcore.WarnLevel, nil
	case "error":
		return zapcore.ErrorLevel, nil
	case "panic":
		return zapcore.PanicLevel, nil
	case "fatal":
		return zapcore.FatalLevel, nil
	default:
		return nil, fmt.Errorf("unrecognized log level: %s", level)
	}
}

// Log returns the current default logger.
func Log() *zap.Logger {
	defaultLoggerMu.RLock()
	defer defaultLoggerMu.RUnlock()
	return defaultLogger.logger
}

// BufferedLog sets the default logger to one that buffers
// logs before a config is loaded.
// Returns the buffered logger, the original default logger
// (for flushing on errors), and the buffer core so that the
// caller can flush the logs after the config is loaded or
// fails to load.
func BufferedLog() (*zap.Logger, *zap.Logger, *internal.LogBufferCore) {
	defaultLoggerMu.Lock()

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Use one of: DEBUG, INFO, WARN, ERROR, PANIC, FATAL (case-insensitive).
  2. Remove the level line entirely — empty defaults to INFO.
  3. If you need trace-level verbosity, note Caddy has no TRACE level; use DEBUG.

Example fix

// before (caddyfile)
{
    log {
        level TRACE
    }
}

// after
{
    log {
        level DEBUG
    }
}
Defensive patterns

Strategy: validation

Validate before calling

var allowedLevels = map[string]bool{"": true, "debug": true, "info": true, "warn": true, "error": true, "panic": true, "fatal": true}

func levelOK(s string) bool { return allowedLevels[strings.ToLower(strings.TrimSpace(s))] }

Try / catch

if err := caddy.Validate(cfg); err != nil {
    if strings.Contains(err.Error(), "unrecognized log level") {
        // replace with debug/info/warn/error/panic/fatal
    }
    return err
}

Prevention

When it happens

Trigger: level set to 'trace', 'verbose', 'notice', 'WARNING' with a typo like 'warnning', or any string not in the accepted set.

Common situations: Porting configs from other servers whose level names differ (nginx's 'warn' works, but syslog's 'notice' does not); assuming 'trace' exists because OpenTelemetry or zap docs mention it; case is fine (it is lowercased) but spelling must match exactly.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/45fca6cadf174838. Report an issue: GitHub.