caddyserver/caddy · error

connection policy %d: building standard TLS config: %s

Error message

connection policy %d: building standard TLS config: %s

What it means

Returned by ConnectionPolicies.Provision when ConnectionPolicy.buildStandardTLSConfig fails for connection policy index i. It is a wrapper around every error buildStandardTLSConfig can produce: getting the tls app, unsupported cipher suite names, bad curves, min>max protocol versions, and client-CA provisioning/configuring failures. The index tells you which policy in the ordered list is broken.

Source

Thrown at modules/caddytls/connpolicy.go:71

	for i, pol := range cp {
		// matchers
		mods, err := ctx.LoadModule(pol, "MatchersRaw")
		if err != nil {
			return fmt.Errorf("loading handshake matchers: %v", err)
		}
		for _, modIface := range mods.(map[string]any) {
			cp[i].matchers = append(cp[i].matchers, modIface.(ConnectionMatcher))
		}

		// enable HTTP/2 by default
		if pol.ALPN == nil {
			pol.ALPN = append(pol.ALPN, defaultALPN...)
		}

		// pre-build standard TLS config so we don't have to at handshake-time
		err = pol.buildStandardTLSConfig(ctx)
		if err != nil {
			return fmt.Errorf("connection policy %d: building standard TLS config: %s", i, err)
		}

		if pol.ClientAuthentication != nil && len(pol.ClientAuthentication.VerifiersRaw) > 0 {
			clientCertValidations, err := ctx.LoadModule(pol.ClientAuthentication, "VerifiersRaw")
			if err != nil {
				return fmt.Errorf("loading client cert verifiers: %v", err)
			}
			for _, validator := range clientCertValidations.([]any) {
				cp[i].ClientAuthentication.verifiers = append(cp[i].ClientAuthentication.verifiers, validator.(ClientCertificateVerifier))
			}
		}

		if len(pol.HandshakeContextRaw) > 0 {
			modIface, err := ctx.LoadModule(pol, "HandshakeContextRaw")
			if err != nil {
				return fmt.Errorf("loading handshake context module: %v", err)
			}
			cp[i].handshakeContext = modIface.(HandshakeContext)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Unwrap the inner error text: it states the exact sub-failure (cipher suite, protocol range, client CA, etc.)
  2. Map the policy index i to the i-th site/policy in your config and fix that block
  3. Fix the specific cause: correct cipher names, order protocol_min <= protocol_max, repair the trust_pool
  4. Validate with 'caddy validate --config <file>' before reload

Example fix

# before
example.com {
	tls {
		protocol_version tls1.3 tls1.2
	}
}

# after (min first, max second)
example.com {
	tls {
		protocol_version tls1.2 tls1.3
	}
}
Defensive patterns

Strategy: try-catch

Try / catch

// Unwrap to reach the concrete cause:
if err := pol.buildStandardTLSConfig(ctx); err != nil {
	var target *tls.UnsupportedError // example; real cause varies
	if errors.As(err, &target) { /* handle specifically */ }
	return fmt.Errorf("policy failed: %w", err)
}

Prevention

When it happens

Trigger: The i-th connection policy contains an invalid cipher_suite name, protocol_min > protocol_max, a client auth block with an unloadable trust pool, or runs in a context where the tls app failed to load. Caddyfile routes with tls protocol_versions/ciphers in the wrong order or misspelled.

Common situations: Typo in a cipher suite name copied from a hardening guide (e.g. TLS_ names for TLS 1.3 suites, which are not configurable); protocol_min tls1.3 with protocol_max tls1.2; multiple sites where one has a bad TLS block and the index in the message points at it.

Understand the failure class

Related errors


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