nats-io/nats-server · error

NCryptOpenStorageProvider returned %X: %v

Error message

NCryptOpenStorageProvider returned %X: %v

What it means

NCryptOpenStorageProvider failed to open the requested Windows key storage provider (e.g. the CNG 'Microsoft Software Key Storage Provider' or a TPM/smartcard provider). The NATS server calls NCryptOpenStorageProvider via syscall when opening the certificate store for TLS client-cert auth; the returned NTSTATUS (r) and the Go syscall error are wrapped into this message. Without a provider handle the server cannot enumerate certificates, so key-store-backed TLS identity setup fails.

Source

Thrown at server/certstore/certstore_windows.go:316

// winWide returns a pointer to uint16 representing the equivalent
// to a Windows LPCWSTR.
func winWide(s string) *uint16 {
	w := utf16.Encode([]rune(s))
	w = append(w, 0)
	return &w[0]
}

// winOpenProvider gets a provider handle for subsequent calls
func winOpenProvider(provider string) (uintptr, error) {
	var hProv uintptr
	pname := winWide(provider)
	// Open the provider, the last parameter is not used
	r, _, err := winNCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&hProv)), uintptr(unsafe.Pointer(pname)), 0)
	if r == 0 {
		return hProv, nil
	}
	return hProv, fmt.Errorf("NCryptOpenStorageProvider returned %X: %v", r, err)
}

// winFindCert wraps the CertFindCertificateInStore library call. Note that any cert context passed
// into prev will be freed. If no certificate was found, nil will be returned.
func winFindCert(store windows.Handle, enc, findFlags, findType uint32, para *uint16, prev *windows.CertContext) (*windows.CertContext, error) {
	h, _, err := winCertFindCertificateInStore.Call(
		uintptr(store),
		uintptr(enc),
		uintptr(findFlags),
		uintptr(findType),
		uintptr(unsafe.Pointer(para)),
		uintptr(unsafe.Pointer(prev)),
	)
	if h == 0 {
		// Actual error, or simply not found?
		if errno, ok := err.(syscall.Errno); ok && errno == syscall.Errno(winCryptENotFound) {
			return nil, ErrFailedCertSearch
		}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check the %X NTSTATUS in the message and look it up (e.g. 0x80090016 = NTE_BAD_KEYSET: keyset does not exist).
  2. Verify the provider name in your TLS config matches an installed provider (certutil -csplist or ncrypt providers list).
  3. Ensure the account running the NATS server (LocalSystem/service account) has access to the required key store; key stores are per-user.
  4. If the keyset is corrupt, recreate the certificate/key pair or import the PFX into the target store with certlm.msc/certutil.
  5. Ensure required services (TPM service, smartcard service) are running when using hardware providers.

Example fix

// before
opts.TLSConfig.CertStore = "Microsoft Sofware Key Storage Provider" // typo
// after
opts.TLSConfig.CertStore = "Microsoft Software Key Storage Provider"
Defensive patterns

Strategy: fallback

Validate before calling

// PowerShell: verify the provider exists before configuring the server
certutil -csplist | Select-String "Provider Name"

Try / catch

if err := server.Start(); err != nil && strings.Contains(err.Error(), "NCryptOpenStorageProvider") {
    // parse NTSTATUS %X, log actionable message, and fall back to a PEM-file TLS config
    log.Fatalf("key store unavailable (%v); use cert_file/key_file instead", err)
}

Prevention

When it happens

Trigger: Calling winOpenProvider (via winOpenCertStore during NATS startup with a certstore-based TLS config on Windows) when: the provider name string is misspelled or not installed, the key store service is unavailable, or NCryptOpenStorageProvider returns a nonzero NTSTATUS (e.g. NTE_BAD_KEYSET 0x80090016, NTE_PROV_TYPE_NOT_DEF).

Common situations: Windows machine with corrupted or missing key containers; requesting a TPM or smartcard provider whose driver/service is not running; running as a service account without access to the user key store; typo in the configured provider name.

Related errors


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