caddyserver/caddy · error

handshake context: %v

Error message

handshake context: %v

What it means

Returned inside the per-handshake GetCertificate callback when a configured HandshakeContext module's HandshakeContext(hello) call returned an error. The module is explicitly allowed to abort the handshake by erroring; this wrapper surfaces that decision with the 'handshake context:' prefix.

Source

Thrown at modules/caddytls/connpolicy.go:313

			cfg := *tlsApp.getConfigForName(hello.ServerName)
			if p.CertSelection != nil {
				// you would think we could just set this whether or not
				// p.CertSelection is nil, but that leads to panics if
				// it is, because cfg.CertSelection is an interface,
				// so it will have a non-nil value even if the actual
				// value underlying it is nil (sigh)
				cfg.CertSelection = p.CertSelection
			}
			cfg.DefaultServerName = p.DefaultSNI
			cfg.FallbackServerName = p.FallbackSNI

			// TODO: experimental: if a handshake context module is configured, allow it
			// to modify the context before passing it into CertMagic's GetCertificate
			ctx := hello.Context()
			if p.handshakeContext != nil {
				ctx, err = p.handshakeContext.HandshakeContext(hello)
				if err != nil {
					return nil, fmt.Errorf("handshake context: %v", err)
				}
			}

			return cfg.GetCertificateWithContext(ctx, hello)
		},
		MinVersion: tls.VersionTLS12,
		MaxVersion: tls.VersionTLS13,
	}

	// session tickets support
	if tlsApp.SessionTickets != nil {
		cfg.SessionTicketsDisabled = tlsApp.SessionTickets.Disabled

		// session ticket key rotation
		tlsApp.SessionTickets.register(cfg)
		ctx.OnCancel(func() {
			// do cleanup when the context is canceled because,
			// though unlikely, it is possible that a context

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Identify the handshake context module from the policy config and check its docs/logs for why it errors
  2. If the error is an intentional rejection, fix the client or the module's criteria
  3. If it is a plugin bug, gather the ClientHello details from logs and report upstream
  4. Temporarily remove handshake_context_raw from the policy to confirm it is the source
Defensive patterns

Strategy: try-catch

Try / catch

// In a custom HandshakeContext implementation, classify errors:
cctx, err := hsModule.HandshakeContext(hello)
if err != nil {
	if errors.Is(err, errRejectedByPolicy) {
		// intended rejection: log at info and abort handshake
	} else {
		// unexpected: log at error with ClientHello details for debugging
	}
}

Prevention

When it happens

Trigger: A connection policy with a handshake_context_raw module whose implementation returns an error for the current ClientHello (e.g. policy-based blocking, missing request metadata it needs, internal failure). Fails one handshake at a time, not the whole config load.

Common situations: Plugin-provided handshake context performing extra checks (client fingerprint filtering, mTLS metadata extraction) rejecting a client; plugin bug or missing dependency at handshake time; experimental features failing only for certain clients.

Understand the failure class

Related errors


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