FiloSottile/mkcert · warning

no certs found

Error message

no certs found

What it means

mkcert's uninstall path walks the Windows ROOT system store and deletes every certificate whose serial number equals the local CA's serial. If the enumeration completes but nothing matched, it synthesizes 'no certs found' and fatalIfErr terminates. It almost always means the CA was never installed on this machine, was already uninstalled, or the CA (and thus its serial number) changed since installation.

Source

Thrown at truststore_windows.go:63

	// Open root store
	store, err := openWindowsRootStore()
	fatalIfErr(err, "open root store")
	defer store.close()
	// Add cert
	fatalIfErr(store.addCert(cert), "add cert")
	return true
}

func (m *mkcert) uninstallPlatform() bool {
	// We'll just remove all certs with the same serial number
	// Open root store
	store, err := openWindowsRootStore()
	fatalIfErr(err, "open root store")
	defer store.close()
	// Do the deletion
	deletedAny, err := store.deleteCertsWithSerial(m.caCert.SerialNumber)
	if err == nil && !deletedAny {
		err = fmt.Errorf("no certs found")
	}
	fatalIfErr(err, "delete cert")
	return true
}

type windowsRootStore uintptr

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)
}

View on GitHub (pinned to 1c1dc4ed27)

Solutions

  1. If the goal is simply a clean store, treat this as success: the CA is not present, nothing to remove.
  2. Check the Windows ROOT store (certmgr.msc -> Trusted Root Certification Authorities) for a leftover 'mkcert developed by FiloSottile' entry and delete it manually if the serial changed.
  3. If a genuine stale entry with a different serial exists, rerun `mkcert -install` with the original CAROOT first so the serials match, then `mkcert -uninstall`.
  4. In scripted cleanup, guard the call: only uninstall when an install previously succeeded in the same run.

Example fix

// before: unconditional cleanup fails on fresh machines
mkcert -uninstall

// after: only uninstall if this run installed it
if [ "$INSTALLED_MKCERT" = "1" ]; then mkcert -uninstall; fi
Defensive patterns

Strategy: validation

Validate before calling

out, err := exec.Command("certutil", "-store", "ROOT").CombinedOutput()
if err == nil && !strings.Contains(string(out), "mkcert") {
    // nothing to uninstall; skip `mkcert -uninstall`
    return nil
}

Prevention

When it happens

Trigger: Running `mkcert -uninstall` when `mkcert -install` never ran on this host; running it a second time after a successful uninstall; deleting CAROOT and letting mkcert generate a fresh CA (new serial) before uninstalling, so the old store entry's serial no longer matches.

Common situations: CI or container images that blindly run `mkcert -uninstall` in a cleanup step; sharing/syncing a CAROOT between machines so serials diverge from what is actually in each machine's store; a teammate resetting CAROOT then trying to clean up the old install.

Related errors


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