labstack/echo · error
panic: err from config.ToMiddleware() in RequestLoggerWithCo
Error message
panic: err from config.ToMiddleware() in RequestLoggerWithConfig
What it means
This panic is raised by RequestLoggerWithConfig when config.ToMiddleware() returns a non-nil error. The only validation ToMiddleware performs is at request_logger.go:255-257: it requires config.LogValuesFunc to be non-nil (the field doc at line 131 explicitly marks it 'Mandatory'). Because RequestLoggerWithConfig has no way to surface the error to the caller, it panics with the underlying error value rather than propagating it through the Echo middleware registration path.
Source
Thrown at middleware/request_logger.go:240
ResponseSize int64
// Headers are list of headers from request. Note: request can contain more than one header with same value so slice
// of values is what will be returned/logged for each given header.
// Note: header values are converted to canonical form with http.CanonicalHeaderKey as this how request parser converts header
// names to. For example, the canonical key for "accept-encoding" is "Accept-Encoding".
Headers map[string][]string
// QueryParams are list of query parameters from request URI. Note: request can contain more than one query parameter
// with same name so slice of values is what will be returned/logged for each given query param name.
QueryParams map[string][]string
// FormValues are list of form values from request body+URI. Note: request can contain more than one form value with
// same name so slice of values is what will be returned/logged for each given form value name.
FormValues map[string][]string
}
// RequestLoggerWithConfig returns a RequestLogger middleware with config.
func RequestLoggerWithConfig(config RequestLoggerConfig) echo.MiddlewareFunc {
mw, err := config.ToMiddleware()
if err != nil {
panic(err)
}
return mw
}
// ToMiddleware converts RequestLoggerConfig into middleware or returns an error for invalid configuration.
func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Skipper == nil {
config.Skipper = DefaultSkipper
}
now := time.Now
if config.timeNow != nil {
now = config.timeNow
}
if config.LogValuesFunc == nil {
return nil, errors.New("missing LogValuesFunc callback function for request logger middleware")
}
View on GitHub (pinned to 05489dc173)
Solutions
- Set the LogValuesFunc field in your RequestLoggerConfig — it is mandatory and must be a non-nil func(c *echo.Context, v middleware.RequestLoggerValues) error.
- If you want default behavior with no custom sink, use the zero-argument middleware.RequestLogger() constructor (request_logger.go:395) which wires its own LogValuesFunc to c.Logger() for you.
- If configuration is built dynamically or from external input, call config.ToMiddleware() directly so you receive the error instead of panicking, then handle or log it before registering the middleware.
- Add a nil check before e.Use(): if cfg.LogValuesFunc == nil { return fmt.Errorf("LogValuesFunc is required") }.
Example fix
// before
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
}))
// after
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error {
fmt.Printf("uri=%s status=%d\n", v.URI, v.Status)
return nil
},
})) Defensive patterns
Strategy: validation
Validate before calling
// Validate before registering the middleware
func buildRequestLogger(cfg middleware.RequestLoggerConfig) (echo.MiddlewareFunc, error) {
if cfg.LogValuesFunc == nil {
return nil, errors.New("RequestLoggerConfig.LogValuesFunc is mandatory")
}
return cfg.ToMiddleware() // returns (mw, err) instead of panicking
}
// usage
mw, err := buildRequestLogger(cfg)
if err != nil {
log.Fatal(err)
}
e.Use(mw) Type guard
// Compile-time guarantee that the config carries a non-nil callback.
// (Go has no structural type guard; use a constructor that enforces it.)
func NewRequestLogger(logValuesFunc func(c *echo.Context, v middleware.RequestLoggerValues) error, opts ...func(*middleware.RequestLoggerConfig)) echo.MiddlewareFunc {
if logValuesFunc == nil {
panic("NewRequestLogger: logValuesFunc must not be nil")
}
cfg := middleware.RequestLoggerConfig{LogValuesFunc: logValuesFunc}
for _, opt := range opts {
opt(&cfg)
}
mw, err := cfg.ToMiddleware()
if err != nil {
panic(err)
}
return mw
} Try / catch
// Go has no try/catch; recover in main() only as a last-resort guard during
// application bootstrap. Prefer validation. If you must isolate panics during
// wiring, wrap e.Use calls:
func safeUse(e *echo.Echo, name string, build func() echo.MiddlewareFunc) {
defer func() {
if r := recover(); r != nil {
log.Fatalf("failed to register %s: %v", name, r)
}
}()
e.Use(build())
}
safeUse(e, "request-logger", func() echo.MiddlewareFunc {
return middleware.RequestLoggerWithConfig(cfg)
}) Prevention
- Treat LogValuesFunc as a required constructor argument: write a small wrapper/constructor that accepts the callback as its first parameter so it can never be omitted.
- Prefer config.ToMiddleware() over RequestLoggerWithConfig when the config is built from dynamic or external sources — it returns an error instead of panicking.
- For default logging with no custom sink, use middleware.RequestLogger() instead of building a RequestLoggerConfig yourself.
- Add a startup unit test that exercises e.Use(...) on a freshly built Echo instance to fail-fast in CI rather than at runtime.
- Keep the callback assignment co-located with the RequestLoggerConfig literal rather than assigning it later in a separate code path.
When it happens
Trigger: Calling middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{...}) with a struct literal that omits the LogValuesFunc field, or sets it to nil. This commonly happens when a developer copies a Logger() config (which needs no callback) and forgets that the RequestLogger variant is callback-driven, or when LogValuesFunc is conditionally assigned (e.g. behind an env flag) and the branch that leaves it unset executes at startup.
Common situations: Migrating from the older Logger()/LoggerWithConfig middleware to the newer RequestLogger API and assuming it has sane defaults; refactoring that accidentally drops the LogValuesFunc assignment; wiring the logger conditionally (dev vs prod) where one path leaves it nil; initializing the config in one place and assigning the callback in another that hasn't run yet by the time e.Use() is called.
Related errors
- echo basic-auth middleware requires a validator function
- echo body-dump middleware requires a handler function
- invalid gzip level
- missing LogValuesFunc callback function for request logger m
- timeout must be set
AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04).
Data as JSON: /data/errors/c7a7d5f231e9cea2.json.
Report an issue: GitHub.