dotnet/maui · error · Exception
Cert {certificateThumbprint} exists in LocalMachine\TrustedP
Error message
Cert {certificateThumbprint} exists in LocalMachine\TrustedPeople but its private key is not accessible from this non-elevated process, and removing the stale cert also requires elevation. Please remove the stale entries manually and re-run this task elevated once:
Remove-Item Cert:\LocalMachine\TrustedPeople\{certificateThumbprint}
Remove-Item Cert:\CurrentUser\My\{certificateThumbprint} What it means
Thrown in GenerateMsixCert when an existing cert (by thumbprint) is found in LocalMachine\TrustedPeople but IsCurrentUserSigningCertUsable returns false (private key in an inaccessible machine key container), and the attempt to remove the stale cert from both LocalMachine\TrustedPeople and CurrentUser\My throws CryptographicException — because deleting from LocalMachine requires elevation that the current non-elevated process lacks. The message instructs manual removal with elevated PowerShell.
Source
Thrown at eng/devices/windows.cake:101
localTrustedPeopleStore.Close();
// If a cert exists, verify it has a usable user-scoped private key in CurrentUser\My. A cert
// installed by an older version of this script may reference a private key in the machine key
// container (C:\ProgramData\Microsoft\Crypto\...), which is unreadable from a non-elevated
// process — signtool would then fail mid-build with an opaque "No certificates were found that
// met all the given criteria". If unusable, remove the stale entries and fall through to the
// creation path below.
if (!string.IsNullOrEmpty(certificateThumbprint) && !IsCurrentUserSigningCertUsable(certificateThumbprint))
{
Information("Existing cert {0} has no usable user-scoped private key; removing and recreating.", certificateThumbprint);
try
{
RemoveCertByThumbprint(StoreLocation.LocalMachine, "TrustedPeople", certificateThumbprint);
RemoveCertByThumbprint(StoreLocation.CurrentUser, "My", certificateThumbprint);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
throw new Exception(
"Cert " + certificateThumbprint + " exists in LocalMachine\\TrustedPeople but its private key " +
"is not accessible from this non-elevated process, and removing the stale cert also requires " +
"elevation. Please remove the stale entries manually and re-run this task elevated once:\n" +
" Remove-Item Cert:\\LocalMachine\\TrustedPeople\\" + certificateThumbprint + "\n" +
" Remove-Item Cert:\\CurrentUser\\My\\" + certificateThumbprint,
ex);
}
certificateThumbprint = null;
}
if (string.IsNullOrEmpty(certificateThumbprint))
{
Information("Generating cert");
var rsa = RSA.Create();
var req = new CertificateRequest("CN=" + certCN, rsa, System.Security.Cryptography.HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection
{View on GitHub (pinned to f377ff1c5e)
Solutions
- Run the two Remove-Item commands from an elevated PowerShell exactly as the message specifies, then re-run the task (the creation path will make a user-keyed cert going forward).
- Run the whole task elevated once; after the new user-keyed cert is created, subsequent non-elevated runs reuse it.
- If you cannot elevate, use a different commonName (--commonname) so a fresh cert is created without touching the stale one.
- After cleanup, verify with IsCurrentUserSigningCertUsable-style logic that the new cert's key is user-scoped before building the MSIX.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before the task, detect the stale-cert condition non-destructively
var existing = new X509Store("TrustedPeople", StoreLocation.LocalMachine);
existing.Open(OpenFlags.ReadOnly);
var stale = existing.Certificates.Cast<X509Certificate2>()
.FirstOrDefault(c => c.Subject == "CN=" + certCN && !IsCurrentUserSigningCertUsable(c.Thumbprint));
existing.Close();
if (stale != null)
Information($"Stale cert {stale.Thumbprint} detected; an elevated run is needed to remove it."); Try / catch
// The existing catch already wraps CryptographicException; surface a fix-it message and halt
catch (System.Security.Cryptography.CryptographicException ex)
{
Error($"Run elevated once to remove stale cert {certificateThumbprint}, then re-run non-elevated.");
throw new Exception("Stale cert requires one-time elevation to remove.", ex);
} Prevention
- Run GenerateMsixCert elevated once after upgrading scripts so the new user-keyed cert replaces any machine-keyed one.
- Avoid deleting the cert after first creation to prevent re-triggering the elevation requirement.
- Use a distinct --commonname when you cannot elevate, to sidestep a stale cert.
When it happens
Trigger: A cert created by an older version of this script (which used MachineKeySet) is still in the stores; running the packaged test task non-elevated on a machine where that stale cert exists; the non-elevated process can read the store but cannot delete from LocalMachine.
Common situations: Upgrading the repo/scripts on a dev machine that previously ran an older cert-generation flow; shared CI runner where a prior job left a machine-container-keyed cert; switching from elevated to non-elevated runs after the cert was installed by an admin.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to install signing cert into LocalMachine\TrustedPeop
- Error: Couldn't find .cer or .msix file
- Failed to install app MSIX (exit code {installExit}): {msixP
- ActivateApplication failed (HRESULT=0x{0:X8})
- Category discovery run did not complete successfully
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/841c8a82e4d6ae22.
Report an issue: GitHub.