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

  1. Only use slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, or slog.LevelError with this logger.
  2. Clamp or map custom slog levels to the nearest supported level before logging.
  3. 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

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


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/5808539d4d05c0da. Report an issue: GitHub.