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
- Set HSTSMaxAge to 0 (Go zero value) to effectively disable HSTS, or to a positive duration in seconds such as 31536000 (one year).
- If the value is computed, clamp it before passing to helmet.New: if v < 0 { v = 0 }.
- 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
- Never use -1 as a 'disabled' sentinel for HSTSMaxAge — use 0 to disable HSTS.
- When computing max-age from a time delta, clamp the result to >= 0 before assigning.
- Validate signed-int config values at the loader boundary, not at middleware construction.
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
- helmet: HSTSPreloadEnabled requires HSTSExcludeSubdomains…
- ErrTagInvalid
- ErrUnknownTag
- ErrUpstreamSchemeNotAllowed
- favicon: file size exceeds max bytes
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)