caddyserver/caddy · error

getting tls app: %v

Error message

getting tls app: %v

What it means

Returned by ConnectionPolicy.buildStandardTLSConfig when ctx.App("tls") fails to retrieve the running TLS app while a connection policy is being built. Because connection policies are built during the TLS app's own provisioning, this error indicates a fundamental config/context wiring problem (the tls app module itself failed or is not in the config) rather than anything operator-fixable per-policy.

Source

Thrown at modules/caddytls/connpolicy.go:272

	// so it can be minimally adjusted after provisioning
	// if necessary (like to adjust NextProtos to disable HTTP/2),
	// and may be unexported in the future.
	TLSConfig *tls.Config `json:"-"`
}

type HandshakeContext interface {
	// HandshakeContext returns a context to pass into CertMagic's
	// GetCertificate function used to serve, load, and manage certs
	// during TLS handshakes. Generally you'll start with the context
	// from the ClientHelloInfo, but you may use other information
	// from it as well. Return an error to abort the handshake.
	HandshakeContext(*tls.ClientHelloInfo) (context.Context, error)
}

func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
	tlsAppIface, err := ctx.App("tls")
	if err != nil {
		return fmt.Errorf("getting tls app: %v", err)
	}
	tlsApp := tlsAppIface.(*TLS)

	// fill in some "easy" default values, but for other values
	// (such as slices), we should ensure that they start empty
	// so the user-provided config can fill them in; then we will
	// fill in a default config at the end if they are still unset
	cfg := &tls.Config{
		NextProtos: p.ALPN,
		GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
			// TODO: I don't love how this works: we pre-build certmagic configs
			// so that handshakes are faster. Unfortunately, certmagic configs are
			// comprised of settings from both a TLS connection policy and a TLS
			// automation policy. The only two fields (as of March 2020; v2 beta 17)
			// of a certmagic config that come from the TLS connection policy are
			// CertSelection and DefaultServerName, so an automation policy is what
			// builds the base certmagic config. Since the pre-built config is
			// shared, I don't think we can change any of its fields per-handshake,

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Ensure Provision/TLSConfig is called with the caddy.Context from a config that includes a tls app
  2. If embedding, register and provision the tls app before building connection policies
  3. Inspect earlier log lines/errors: the tls app load failure is the root cause and is reported before this wrapper
  4. Simplify the config to isolate which top-level app fails to load
Defensive patterns

Strategy: try-catch

Try / catch

// Embedders: ensure the tls app is loaded before building policies
_, err := ctx.App("tls")
if err != nil {
	return fmt.Errorf("tls app unavailable, cannot build policies: %w", err)
}

Prevention

When it happens

Trigger: Calling ConnectionPolicies.Provision/TLSConfig outside a properly initialized caddy.Context, or a config where the tls app failed to load earlier and error propagation reached policy building. Almost exclusively seen by embedders and plugin authors invoking these APIs with a hand-made context.

Common situations: Unit tests or custom embedders building connection policies with a context lacking the tls app; internal error paths during partial config loads. End users of stock caddy essentially never see it in isolation.

Understand the failure class

Related errors


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