FiloSottile/mkcert · warning

failed to close windows root store

Error message

failed to close windows root store: %v

What it means

After installing or uninstalling, mkcert closes the ROOT store handle with CertCloseStore(handle, 0); if the API returns 0 the formatted error is returned. Because the handle is closed via `defer store.close()` after the operation already succeeded, this failure is cosmetic — the store mutation completed but the handle teardown failed (typically a handle/allocation issue or the store already closed). mkcert does not call fatalIfErr on this path's result in the defer, so impact is limited to resource hygiene.

Solutions

  1. Treat as non-fatal: the add/delete operation already completed; re-run `mkcert -check` or inspect the ROOT store to confirm the CA state.
  2. Ensure only one mkcert instance manipulates the store at a time to avoid handle races.
  3. Reboot (or restart the Cryptographic Services) if the store is in a bad state and retry.
  4. If reproducible, report upstream to the mkcert project with the GetLastError value.
Defensive patterns

Strategy: try-catch

Try / catch

if err := store.close(); err != nil {
    // operation already succeeded; log and continue, do not fail the run
    log.Printf("warning: store close failed: %v", err)
}

Prevention

When it happens

Trigger: CertCloseStore returning FALSE because the handle is invalid or was already closed; internal cert-context leaks making close fail; running on a Windows version where the store was invalidated between open and close (e.g. store service restarted mid-operation).

Common situations: Rare in practice; occasionally observed after AV interference with crypt32 or in long-lived processes that manipulate the store repeatedly; mostly seen when the same store handle is closed twice due to upstream code changes.

Related errors


AI-assisted analysis of FiloSottile/mkcert@1c1dc4ed27 (2026-08-15). Data as JSON: /api/errors/b6ce976c0564134e. Report an issue: GitHub.

Appendix: source

Thrown at truststore_windows.go:88

func openWindowsRootStore() (windowsRootStore, error) {
	rootStr, err := syscall.UTF16PtrFromString("ROOT")
	if err != nil {
		return 0, err
	}
	store, _, err := procCertOpenSystemStoreW.Call(0, uintptr(unsafe.Pointer(rootStr)))
	if store != 0 {
		return windowsRootStore(store), nil
	}
	return 0, fmt.Errorf("failed to open windows root store: %v", err)
}

func (w windowsRootStore) close() error {
	ret, _, err := procCertCloseStore.Call(uintptr(w), 0)
	if ret != 0 {
		return nil
	}
	return fmt.Errorf("failed to close windows root store: %v", err)
}

func (w windowsRootStore) addCert(cert []byte) error {
	// TODO: ok to always overwrite?
	ret, _, err := procCertAddEncodedCertificateToStore.Call(
		uintptr(w), // HCERTSTORE hCertStore
		uintptr(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING), // DWORD dwCertEncodingType
		uintptr(unsafe.Pointer(&cert[0])),                              // const BYTE *pbCertEncoded
		uintptr(len(cert)),                                             // DWORD cbCertEncoded
		3,                                                              // DWORD dwAddDisposition (CERT_STORE_ADD_REPLACE_EXISTING is 3)
		0,                                                              // PCCERT_CONTEXT *ppCertContext
	)
	if ret != 0 {
		return nil
	}
	return fmt.Errorf("failed adding cert: %v", err)
}

View on GitHub (pinned to 1c1dc4ed27)