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

  1. Set config.Timeout to a positive time.Duration, e.g. ContextTimeoutConfig{Timeout: 30 * time.Second}.
  2. Prefer the shorthand ContextTimeout(30 * time.Second) when you only need the timeout.
  3. If loading the duration dynamically, guard it: if d <= 0, fall back to a sane default or fail config loading explicitly.
  4. 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

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


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/a34c5e705026d9d3.json. Report an issue: GitHub.