caddyserver/caddy · error
invalid TLS renegotiation level: %v
Error message
invalid TLS renegotiation level: %v
What it means
While building a tls.Config for a CA pool source, the configured `renegotiation` value did not match any of the allowed levels. Only "never" (or empty), "once", and "freely" map to tls.RenegotiateNever, tls.RenegotiateOnceAsClient, and tls.RenegotiateFreelyAsClient respectively; anything else is rejected.
Source
Thrown at modules/caddytls/capools.go:617
if t.CARaw != nil {
caRaw, err := ctx.LoadModule(t, "CARaw")
if err != nil {
return nil, err
}
ca := caRaw.(CA)
cfg.RootCAs = ca.CertPool()
}
// Renegotiation
switch t.Renegotiation {
case "never", "":
cfg.Renegotiation = tls.RenegotiateNever
case "once":
cfg.Renegotiation = tls.RenegotiateOnceAsClient
case "freely":
cfg.Renegotiation = tls.RenegotiateFreelyAsClient
default:
return nil, fmt.Errorf("invalid TLS renegotiation level: %v", t.Renegotiation)
}
// override for the server name used verify the TLS handshake
cfg.ServerName = repl.ReplaceKnown(cfg.ServerName, "")
// throw all security out the window
cfg.InsecureSkipVerify = t.InsecureSkipVerify
// only return a config if it's not empty
if reflect.DeepEqual(cfg, new(tls.Config)) {
return nil, nil
}
return cfg, nil
}
// The HTTPCertPool fetches the trusted root certificates from HTTP(S)
// endpoints. The TLS connection properties can be customized, including customView on GitHub (pinned to 50e54ee279)
Solutions
- Set the value to exactly one of: never, once, freely (or omit it — default is never).
- Check for stray whitespace or case differences in the config value.
- Run `caddy validate --config Caddyfile` to catch the typo before reload.
Example fix
# before
trust_pool http https://ca.example.com/bundle.pem {
renegotiation always
}
# after
trust_pool http https://ca.example.com/bundle.pem {
renegotiation freely
} Defensive patterns
Strategy: validation
Validate before calling
// in config generation, whitelist renegotiation values
var validRenegotiation = map[string]bool{"": true, "never": true, "once": true, "freely": true}
func sanitizeRenegotiation(v string) (string, error) {
if !validRenegotiation[v] {
return "", fmt.Errorf("invalid renegotiation %q: must be never, once, or freely", v)
}
return v, nil
} Prevention
- Validate config with `caddy validate` in CI to catch enum typos.
- Omit renegotiation unless a broken peer actually requires it; default (never) is the secure setting.
- Remember values are case-sensitive lowercase.
When it happens
Trigger: Setting `renegotiation <value>` on a trust_pool/tls config where value is e.g. "always", "true", "Never" (case matters), or a typo like "freelly".
Common situations: Porting configs from other servers that use different renegotiation vocabularies; case or spelling mistakes; assuming boolean-like values are accepted.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- no PEM keys specified
- no sources specified for combined CA pool
- unsupported cipher suite: %s
- protocol min (%x) cannot be greater than protocol max (%x)
- could not convert automation policy subject '%s' to punycode
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/d5b6c24af1411ed9.
Report an issue: GitHub.