caddyserver/caddy · error
loading trusted proxies modules: %v
Error message
loading trusted proxies modules: %v
What it means
During http app provisioning, each server's trusted_proxies source module (TrustedProxiesRaw, an IPRangeSource such as static_ranges or a trusted_proxies plugin) is loaded via ctx.LoadModule; failures in resolving the module or its inline config (e.g. malformed CIDR ranges) are wrapped with this message.
Source
Thrown at modules/caddyhttp/app.go:295
// otherwise be exploited by sending an unprotected SNI
// value during a TLS handshake, then putting a protected
// domain in the Host header after establishing connection;
// this is a safe default, but we allow users to override
// it for example in the case of running a proxy where
// domain fronting is desired and access is not restricted
// based on hostname
if srv.StrictSNIHost == nil && srv.hasTLSClientAuth() {
app.logger.Warn("enabling strict SNI-Host enforcement because TLS client auth is configured",
zap.String("server_id", srvName))
trueBool := true
srv.StrictSNIHost = &trueBool
}
// set up the trusted proxies source
for srv.TrustedProxiesRaw != nil {
val, err := ctx.LoadModule(srv, "TrustedProxiesRaw")
if err != nil {
return fmt.Errorf("loading trusted proxies modules: %v", err)
}
srv.trustedProxies = val.(IPRangeSource)
}
// set the default client IP header to read from
if srv.ClientIPHeaders == nil {
srv.ClientIPHeaders = []string{"X-Forwarded-For"}
}
// precompute underscore and dot header allowlist rules
if err := srv.provisionUnderscoreHeaders(); err != nil {
return fmt.Errorf("server %s: %v", srvName, err)
}
if err := srv.provisionDotHeaders(); err != nil {
return fmt.Errorf("server %s: %v", srvName, err)
}
// process each listener addressView on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped error — invalid CIDR text names the bad range; 'module not registered' names a missing module.
- Use valid CIDRs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fd00::/8) or single IPs where supported by the module.
- Rebuild with the plugin if a custom IPRangeSource is intended.
- Validate with 'caddy validate' after edits.
Example fix
// before (caddyfile)
srv0 {
trusted_proxies static_ranges 172.17.0.0/8 10.0.0.0/8 # 172.17 is inside /12, wrong mask style
}
// after
srv0 {
trusted_proxies static_ranges 172.16.0.0/12 10.0.0.0/8
} Defensive patterns
Strategy: validation
Validate before calling
// validate CIDR entries before load
func cidrsOK(ranges []string) error {
for _, r := range ranges {
if _, _, err := net.ParseCIDR(r); err != nil {
if net.ParseIP(r) == nil {
return fmt.Errorf("bad trusted proxy range %q: %w", r, err)
}
}
}
return nil
} Try / catch
if err := caddy.Validate(cfg); err != nil {
if strings.Contains(err.Error(), "loading trusted proxies modules") {
// nested cause names the bad range or missing module — fix and re-validate
}
return err
} Prevention
- Source proxy CIDR lists programmatically (cloud metadata) instead of hand-editing.
- Validate CIDRs with net.ParseCIDR in any config-generation tooling.
- Confirm the IPRangeSource module is compiled in when using third-party sources.
When it happens
Trigger: trusted_proxies static_ranges <ranges> where a range is not a valid CIDR/IP range; a third-party IP range source module not compiled into the binary; JSON with a misspelled module name under trusted_proxies.
Common situations: Copying Docker/Kubernetes CIDR lists with typos or bare IPs where ranges are expected; plugin missing from xcaddy builds; cloud environments where the proxy CIDR list changed and was hand-patched incorrectly.
Related errors
- malformed If-Match header; expect quoted string
- malformed If-Match header; expect format \"<path> <hash>\"
- %s: invalid configuration: %v
- module name not specified with key '%s' in %+v
- server %s: listener protocols count does not match address c
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/27a14b2f1b274ce4.
Report an issue: GitHub.