gofr-dev/gofr · error

IdleConnTimeout cannot be negative

Error message

IdleConnTimeout cannot be negative

What it means

errNegativeIdleConnTimeout is a validation sentinel: ConnectionPoolConfig.Validate rejects a negative IdleConnTimeout because http.Transport cannot use a negative duration for how long idle connections are kept. Validate wraps it with the offending duration before returning.

Source

Thrown at pkg/gofr/service/connection_pool.go:13

package service

import (
	"errors"
	"fmt"
	"net/http"
	"time"
)

var (
	errNegativeMaxIdleConns        = errors.New("MaxIdleConns cannot be negative")
	errNegativeMaxIdleConnsPerHost = errors.New("MaxIdleConnsPerHost cannot be negative")
	errNegativeIdleConnTimeout     = errors.New("IdleConnTimeout cannot be negative")
)

// ConnectionPoolConfig holds the configuration for HTTP connection pool settings.
// It customizes the HTTP transport layer to optimize connection reuse for high-frequency requests.
//
// Note: This configuration must be applied first when using multiple options with AddHTTPService,
// as it needs to access the underlying HTTP client transport. If applied after wrapper options
// (CircuitBreaker, Retry, OAuth), it will be silently ignored.
//
// Example:
//
//	app.AddHTTPService("api-service", "https://api.example.com",
//	    &service.ConnectionPoolConfig{
//	        MaxIdleConns:        100,
//	        MaxIdleConnsPerHost: 20,
//	        IdleConnTimeout:     90 * time.Second,
//	    },
//	    &service.CircuitBreakerConfig{...}, // Other options after ConnectionPoolConfig

View on GitHub (pinned to 187eb24962)

Solutions

  1. Set IdleConnTimeout to zero (default behavior) or a positive duration like 90*time.Second
  2. If you meant 'disabled', use 0 rather than a negative duration
  3. Parse durations with time.ParseDuration and validate the sign at load time
  4. Use errors.Is(err, errNegativeIdleConnTimeout) to map the error back to the config field

Example fix

// before
pool := &ConnectionPoolConfig{IdleConnTimeout: -1 * time.Second} // meant 'no timeout'
// after
pool := &ConnectionPoolConfig{IdleConnTimeout: 0} // 0 = default; or 90 * time.Second
Defensive patterns

Strategy: validation

Validate before calling

if pool.IdleConnTimeout < 0 {
    return fmt.Errorf("IdleConnTimeout must be >= 0, got %v", pool.IdleConnTimeout)
}
if err := pool.Validate(); err != nil { return err }

Type guard

func validTimeout(d time.Duration) bool { return d >= 0 }

Try / catch

if err := pool.Validate(); err != nil {
    if errors.Is(err, errNegativeIdleConnTimeout) {
        pool.IdleConnTimeout = 0 // default behavior
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: ConnectionPoolConfig{IdleConnTimeout: -time.Second} (any negative duration) passed to Validate() or applied through AddOption/AddHTTPService, which validates first.

Common situations: Parsing durations from config where a typo/missing unit or misparsed string becomes negative; intentionally using -1 to mean 'infinite' or 'disabled' (unsupported here); time.Duration arithmetic underflow.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/1aeed5a4ee4c7dd6. Report an issue: GitHub.