gofiber/fiber · error

helmet: HSTSMaxAge must be greater than or equal to 0

Error message

helmet: HSTSMaxAge must be greater than or equal to 0

What it means

The helmet middleware panics during configDefault when Config.HSTSMaxAge is negative. HSTS max-age is emitted verbatim into the Strict-Transport-Security header (e.g. max-age=31536000) and per RFC 6797 it must be a non-negative integer of seconds. A negative value is nonsensical and would produce an invalid header, so helmet fails fast at startup rather than shipping a broken security directive.

Solutions

  1. Set HSTSMaxAge to 0 (Go zero value) to effectively disable HSTS, or to a positive duration in seconds such as 31536000 (one year).
  2. If the value is computed, clamp it before passing to helmet.New: if v < 0 { v = 0 }.
  3. If loading from configuration, validate the parsed int and treat unparseable/negative input as a config-load error rather than forwarding it to helmet.

Example fix

// before
app.Use(helmet.New(helmet.Config{
    HSTSMaxAge: expiry.Sub(time.Now()), // can be negative once expiry passes
}))

// after
maxAge := int(time.Until(expiry).Seconds())
if maxAge < 0 {
    maxAge = 0
}
app.Use(helmet.New(helmet.Config{
    HSTSMaxAge: maxAge,
}))
Defensive patterns

Strategy: validation

Validate before calling

// before calling helmet.New
func sanitizeHSTSMaxAge(v int) int {
    if v < 0 {
        return 0 // or return an error from your config loader
    }
    return v
}

cfg := helmet.Config{HSTSMaxAge: sanitizeHSTSMaxAge(parsedMaxAge)}
app.Use(helmet.New(cfg))

Type guard

func isValidHSTSMaxAge(v int) bool { return v >= 0 }

Prevention

When it happens

Trigger: Passing helmet.Config{HSTSMaxAge: -1} (or any value < 0) to helmet.New. Common when HSTSMaxAge is derived from an int subtraction (e.g. someConstant - delta) that underflows, or when a -1 is used as a 'disabled' sentinel.

Common situations: Loading max-age from an env var parsed as a signed int where the env var is unset and defaults to -1; computing max-age as an expiry offset that goes negative near token expiration; copy-pasting a config block and forgetting to set the field (Go zero-value 0 is fine, so this only fires on an explicit negative).

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/e762b6c032609be6. Report an issue: GitHub.

Appendix: source

Thrown at middleware/helmet/config.go:110

	CrossOriginResourcePolicy: "same-origin",
	OriginAgentCluster:        "?1",
	XDNSPrefetchControl:       "off",
	XDownloadOptions:          "noopen",
	XPermittedCrossDomain:     "none",
}

// Helper function to set default values
func configDefault(config ...Config) Config {
	// Return default config if nothing provided
	if len(config) < 1 {
		return ConfigDefault
	}

	// Override default config
	cfg := config[0]

	if cfg.HSTSMaxAge < 0 {
		panic("helmet: HSTSMaxAge must be greater than or equal to 0")
	}

	if cfg.HSTSPreloadEnabled && cfg.HSTSExcludeSubdomains {
		panic("helmet: HSTSPreloadEnabled requires HSTSExcludeSubdomains to be false")
	}

	// Set default values
	if cfg.XSSProtection == "" {
		cfg.XSSProtection = ConfigDefault.XSSProtection
	}

	if cfg.ContentTypeNosniff == "" {
		cfg.ContentTypeNosniff = ConfigDefault.ContentTypeNosniff
	}

	if cfg.XFrameOptions == "" {
		cfg.XFrameOptions = ConfigDefault.XFrameOptions
	}

View on GitHub (pinned to a105acad6c)