nats-io/nats-server · error

unable to register client OCSP verification

Error message

unable to register client OCSP verification

What it means

Raised in Server.plugClientTLSOCSPPeer (server/ocsp_peer.go:165) when the client-kind TLS wrapper passed from plugTLSOCSPPeer is missing its config, tlsConfig, or tlsOpts, so the OCSP VerifyConnection callback cannot be registered on the client TLS config (certidp.ErrUnableToPlugTLSClient). It is a defensive invariant check that fails server startup rather than allowing OCSP peer verification to be silently skipped.

Source

Thrown at server/ocsp_peer.go:165

	}
	s.Debugf(certidp.DbgPlugTLSForKind, config.kind)
	// peer is a tls client
	if kind == kindStringMap[CLIENT] || (kind == kindStringMap[LEAF] && !isSpoke) {
		if !tcOpts.Verify {
			return nil, false, errors.New(certidp.ErrMTLSRequired)
		}
		return s.plugClientTLSOCSPPeer(config)
	}
	// peer is a tls server
	if kind == kindStringMap[LEAF] && isSpoke {
		return s.plugServerTLSOCSPPeer(config)
	}
	return nil, false, nil
}

func (s *Server) plugClientTLSOCSPPeer(config *tlsConfigKind) (*tls.Config, bool, error) {
	if config == nil || config.tlsConfig == nil || config.tlsOpts == nil {
		return nil, false, errors.New(certidp.ErrUnableToPlugTLSClient)
	}
	tc := config.tlsConfig
	tcOpts := config.tlsOpts
	kind := config.kind
	if tcOpts.OCSPPeerConfig == nil || !tcOpts.OCSPPeerConfig.Verify {
		return tc, false, nil
	}
	tc.VerifyConnection = func(cs tls.ConnectionState) error {
		if !s.tlsClientOCSPValid(cs.VerifiedChains, tcOpts.OCSPPeerConfig) {
			s.sendOCSPPeerRejectEvent(kind, peerFromVerifiedChains(cs.VerifiedChains), certidp.MsgTLSClientRejectConnection)
			return errors.New(certidp.MsgTLSClientRejectConnection)
		}
		return nil
	}
	return tc, true, nil
}

func (s *Server) plugServerTLSOCSPPeer(config *tlsConfigKind) (*tls.Config, bool, error) {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Ensure the full TLS options (tls block parsed into tlsOpts) are loaded before OCSP plugging; do not enable OCSP on a half-parsed config
  2. If embedding the server, populate all fields of the tlsConfigKind (config, tlsConfig, tlsOpts) before calling enableOCSP-related paths
  3. Retry or re-trigger the reload with the complete config; if it persists, capture the config file and report with the NATS server version
Defensive patterns

Strategy: try-catch

Try / catch

// Go: catch the startup failure and retry with a fully loaded config
if err := srv.Start(); err != nil && strings.Contains(err.Error(), "unable to register client OCSP verification") {
    log.Errorf("OCSP client plugging failed: %v; reloading full TLS config", err)
    reloadFullTLSConfig()
    srv.Start()
}

Prevention

When it happens

Trigger: plugClientTLSOCSPPeer receives a *tlsConfigKind whose tlsOpts was nil even though an earlier coarse check passed, or whose tlsConfig is nil — an internal inconsistency when enableOCSP/reloadOCSP assembles the client TLS config while OCSP peer verify is enabled.

Common situations: Partial config loads during hot reload where TLS options are parsed after the OCSP plugging step; custom embedding of the server that constructs tlsConfigKind manually and leaves tlsOpts unset; race during concurrent reload/OCSP enable.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/7bdcf5b5637a8811. Report an issue: GitHub.