googleapis/mcp-toolbox · error
invalid slog level
Error message
invalid slog level
What it means
levelToSeverity is the inverse mapping of SeverityToLevel: it converts a slog.Level string ("DEBUG","INFO","WARN","ERROR") back into the library's Severity constant. It throws this error when the given slog level string is unrecognized, so severity cannot be rendered for output.
Source
Thrown at internal/log/log.go:126
return slog.LevelError, nil
default:
return slog.Level(-5), fmt.Errorf("invalid log level")
}
}
// Returns severity string based on level.
func levelToSeverity(s string) (string, error) {
switch s {
case slog.LevelDebug.String():
return Debug, nil
case slog.LevelInfo.String():
return Info, nil
case slog.LevelWarn.String():
return Warn, nil
case slog.LevelError.String():
return Error, nil
default:
return "", fmt.Errorf("invalid slog level")
}
}
type StructuredLogger struct {
outLogger *slog.Logger
errLogger *slog.Logger
}
// NewStructuredLogger create a Logger that logs messages using JSON.
func NewStructuredLogger(outW, errW io.Writer, logLevel string) (Logger, error) {
//Set log level
var programLevel = new(slog.LevelVar)
slogLevel, err := SeverityToLevel(logLevel)
if err != nil {
return nil, err
}
programLevel.Set(slogLevel)
View on GitHub (pinned to 8cc6e09de2)
Solutions
- Only use slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, or slog.LevelError with this logger.
- Clamp or map custom slog levels to the nearest supported level before logging.
- Handle the returned error in the formatting path by falling back to a default severity (e.g. INFO) instead of dropping the record.
Example fix
// before lvl := slog.Level(-5) // custom trace level sev, err := log.LevelToSeverity(lvl.String()) // after lvl := slog.LevelInfo sev, err := log.LevelToSeverity(lvl.String())
Defensive patterns
Strategy: fallback
Validate before calling
func supportedSlogLevel(l slog.Level) bool {
switch l {
case slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError:
return true
}
return false
} Type guard
func isStandardLevelString(s string) bool {
return s == slog.LevelDebug.String() || s == slog.LevelInfo.String() ||
s == slog.LevelWarn.String() || s == slog.LevelError.String()
} Try / catch
sev, err := log.LevelToSeverity(lvl.String())
if err != nil {
sev = "INFO" // fallback for custom/unknown slog levels
} Prevention
- Only create loggers with the four standard slog levels.
- Clamp custom levels (e.g. level-4 verbosity) into the nearest standard level before rendering.
- Cover the severity-mapping path in unit tests with all levels your app can produce.
When it happens
Trigger: Calling levelToSeverity (via the structured logger's formatting path) with a slog level whose String() is not one of DEBUG/INFO/WARN/ERROR — e.g. custom slog levels like slog.Level(-5).String(), or a raw string like "warning".
Common situations: Application code registers a custom slog.Level (e.g. slog.LevelDebug-4 for tracing) and the structured logger tries to render it; tests pass an arbitrary level string; the level was constructed numerically rather than from constants.
Related errors
- unable to initialize logger: %w
- unable to retrieve logger: %w
- invalid log level
- unable to initialize http log: %w
- unable to get logger from ctx: %s
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/5808539d4d05c0da.
Report an issue: GitHub.