caddyserver/caddy · error

consolidating TLS connection policies for server

Error message

consolidating TLS connection policies for server %d: %v

What it means

Caddyfile adaptation failed while merging/normalizing the TLS connection policies collected for one HTTP server (srv%d). consolidateConnPolicies tries to combine policies that match the same SNI set; if two such policies disagree on a setting that cannot be safely merged (e.g. different ALPN, cipher suites, protocols, client auth), it returns an error that gets wrapped with the server index.

Solutions

  1. Make the tls settings identical for all site blocks that share the same hostnames (or delete the duplicated ones so a single policy remains)
  2. Use different ports or explicit `bind`/server splits so conflicting policies land on different servers instead of being consolidated
  3. Set the conflicting option once in the global `default_sni`/`fallback_sni` options rather than per site
  4. Check the server index (srv0, srv1, ...) in the message to identify which listen group has the clash

Example fix

# before
example.com {
  tls {
    protocols tls1.2
  }
}
example.com:8443 {
  tls {
    protocols tls1.3
  }
}
# after
example.com {
  tls {
    protocols tls1.2 tls1.3
  }
}
Defensive patterns

Strategy: validation

Validate before calling

# Deduplicate tls settings per hostname before adapting; a quick lint pass:
# (conceptual, in your config pipeline)
assert len({block.tls_settings for block in blocks if block.host == host}) <= 1

Try / catch

if err := caddyfileAdapt(cfg); err != nil {
    if strings.Contains(err.Error(), "consolidating TLS connection policies") {
        // surface which server index and dedupe tls blocks
    }
}

Prevention

When it happens

Trigger: A site block whose server (same listen port group) ends up with two or more tls connection policies covering overlapping/same SNI matchers with incompatible settings — e.g. one block sets `tls { protocols }` and another with the same hostname sets `tls { ciphers }` or different `alpn`, so consolidation cannot reconcile them. Also any error surfaced by the per-field conflict checks inside consolidateConnPolicies (errors 127-135).

Common situations: Multiple site blocks on the same port declaring different `tls` settings for the same domain, a global `tls`/`default_sni` global option combined with per-site `tls` blocks that conflict, or copy-pasted site configs where one block has `tls internal` and another has explicit ciphers for the same names.

Understand the failure class

Related errors


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

Appendix: source

Thrown at caddyconfig/httpcaddyfile/httptype.go:1105

		// catch-all/default policy if there isn't one already (it's
		// important that it goes at the end) - see issue #3004:
		// https://github.com/caddyserver/caddy/issues/3004
		// TODO: maybe a smarter way to handle this might be to just make the
		// auto-HTTPS logic at provision-time detect if there is any connection
		// policy missing for any HTTPS-enabled hosts, if so, add it... maybe?
		if addressQualifiesForTLS &&
			!hasCatchAllTLSConnPolicy &&
			(len(srv.TLSConnPolicies) > 0 || !autoHTTPSWillAddConnPolicy || defaultSNI != "" || fallbackSNI != "") {
			srv.TLSConnPolicies = append(srv.TLSConnPolicies, &caddytls.ConnectionPolicy{
				DefaultSNI:  defaultSNI,
				FallbackSNI: fallbackSNI,
			})
		}

		// tidy things up a bit
		srv.TLSConnPolicies, err = consolidateConnPolicies(srv.TLSConnPolicies)
		if err != nil {
			return nil, fmt.Errorf("consolidating TLS connection policies for server %d: %v", i, err)
		}
		srv.Routes = consolidateRoutes(srv.Routes)

		servers[fmt.Sprintf("srv%d", i)] = srv
	}

	if err := applyServerOptions(servers, options, warnings); err != nil {
		return nil, fmt.Errorf("applying global server options: %v", err)
	}

	return servers, nil
}

// sniNames returns the server names a connection policy's sni matcher matches.
// The bool is false when the policy has no sni matcher, or when it does not
// decode - the latter is unexpected enough to warn about rather than silently
// skip, since callers use it to decide whether a hostname needs shielding.
func sniNames(cp *caddytls.ConnectionPolicy, what string, warnings *[]caddyconfig.Warning) ([]string, bool) {

View on GitHub (pinned to 50e54ee279)