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 address

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Read the wrapped error — invalid CIDR text names the bad range; 'module not registered' names a missing module.
  2. 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.
  3. Rebuild with the plugin if a custom IPRangeSource is intended.
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/27a14b2f1b274ce4. Report an issue: GitHub.