labstack/echo · error
timeout must be set
Error message
timeout must be set
What it means
Returned by ContextTimeoutConfig.ToMiddleware when config.Timeout is the zero value (0). The middleware needs a real deadline to derive a context.WithTimeout; a zero duration would expire immediately and is treated as 'unset'. Because ContextTimeoutWithConfig routes through toMiddlewareOrPanic, this surfaces as a panic at server startup unless you call ToMiddleware directly.
Source
Thrown at middleware/context_timeout.go:40
// Timeout configures a timeout for the middleware
Timeout time.Duration
}
// ContextTimeout returns a middleware which returns error (503 Service Unavailable error) to client
// when underlying method returns context.DeadlineExceeded error.
func ContextTimeout(timeout time.Duration) echo.MiddlewareFunc {
return ContextTimeoutWithConfig(ContextTimeoutConfig{Timeout: timeout})
}
// ContextTimeoutWithConfig returns a Timeout middleware with config.
func ContextTimeoutWithConfig(config ContextTimeoutConfig) echo.MiddlewareFunc {
return toMiddlewareOrPanic(config)
}
// ToMiddleware converts Config to middleware.
func (config ContextTimeoutConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Timeout == 0 {
return nil, errors.New("timeout must be set")
}
if config.Skipper == nil {
config.Skipper = DefaultSkipper
}
if config.ErrorHandler == nil {
config.ErrorHandler = func(c *echo.Context, err error) error {
if err != nil && errors.Is(err, context.DeadlineExceeded) {
return echo.ErrServiceUnavailable.Wrap(err)
}
return err
}
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
if config.Skipper(c) {
return next(c)
}View on GitHub (pinned to 05489dc173)
Solutions
- Set config.Timeout to a positive time.Duration, e.g. ContextTimeoutConfig{Timeout: 30 * time.Second}.
- Prefer the shorthand ContextTimeout(30 * time.Second) when you only need the timeout.
- If loading the duration dynamically, guard it: if d <= 0, fall back to a sane default or fail config loading explicitly.
- Call config.ToMiddleware() instead of ContextTimeoutWithConfig if you want the error returned rather than panicked.
Example fix
// before
m := middleware.ContextTimeoutWithConfig(middleware.ContextTimeoutConfig{
ErrorHandler: myHandler,
})
// after
m := middleware.ContextTimeoutWithConfig(middleware.ContextTimeoutConfig{
Timeout: 30 * time.Second,
ErrorHandler: myHandler,
}) Defensive patterns
Strategy: validation
Validate before calling
func contextTimeoutMiddleware(timeout time.Duration, eh func(*echo.Context, error) error) (echo.MiddlewareFunc, error) {
cfg := middleware.ContextTimeoutConfig{Timeout: timeout, ErrorHandler: eh}
if cfg.Timeout <= 0 {
return nil, errors.New("ContextTimeout requires a positive Timeout")
}
return cfg.ToMiddleware()
} Prevention
- Always pass a positive time.Duration to ContextTimeout or set Timeout in the config.
- If the timeout comes from config/env, validate it is > 0 before wiring the middleware.
- Prefer cfg.ToMiddleware() over ContextTimeoutWithConfig(cfg) in wiring code so config errors return instead of panicking.
When it happens
Trigger: Calling ContextTimeoutWithConfig(ContextTimeoutConfig{}) without setting Timeout, calling ContextTimeout(0), or constructing the config and forgetting the Timeout field (its zero value is 0).
Common situations: Developer copies a config struct and deletes the Timeout line; reading the timeout from an env var that is empty so time.ParseDuration is skipped, leaving Timeout at 0; or refactoring from ContextTimeout(30*time.Second) to the WithConfig form and omitting the field.
Related errors
- at least one AllowOrigins is required or UnsafeAllowOriginFu
- echo key-auth middleware requires a validator function
- echo key-auth middleware could not create extractors from Ke
- echo proxy middleware requires balancer
- echo rate limiter store configuration must be provided
AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04).
Data as JSON: /data/errors/a34c5e705026d9d3.json.
Report an issue: GitHub.