-
-
Notifications
You must be signed in to change notification settings - Fork 523
Description
Description
When Stability Matrix detects a Git version mismatch during InstallGitIfNecessary, it attempts to delete the existing PortableGit directory before downloading the new version. This fails with an UnauthorizedAccessException on git.exe, crashing the upgrade process.
Exception
UnauthorizedAccessException: Access to the path 'git.exe' is denied.
Sentry ID: aedf9c2c
Stack Trace
at System.IO.FileSystem.RemoveDirectoryRecursive(String fullPath, WIN32_FIND_DATA& findData, Boolean topLevel)
at System.IO.FileSystem.RemoveDirectory(String fullPath, Boolean recursive)
at StabilityMatrix.Core.Models.FileInterfaces.DirectoryPath.<>c__DisplayClass25_0.<DeleteAsync>b__0()
...
at StabilityMatrix.Avalonia.Helpers.WindowsPrerequisiteHelper.InstallGitIfNecessary(IProgress`1 progress)
at StabilityMatrix.Avalonia.ViewModels.Settings.MainSettingsViewModel.RunGitProcess()
Root Cause Analysis
The relevant code in InstallGitIfNecessary:
if (Directory.Exists(PortableGitInstallDir))
{
await new DirectoryPath(PortableGitInstallDir).DeleteAsync(true);
}The UnauthorizedAccessException is thrown by RemoveDirectoryRecursive when trying to delete git.exe. Two likely causes have been identified:
-
Git process still running in background — If a
git.exeprocess spawned by Stability Matrix is still alive (e.g. a previous git operation didn't fully exit), Windows will deny deletion of the executable because it is locked by the running process. The affected user confirmed thatgit.exedid not have the read-only attribute set, which points to this as the primary cause. -
Read-only file attributes — In some environments, files inside the PortableGit distribution may carry the read-only attribute, which also causes
UnauthorizedAccessExceptionon deletion.
Suggested Fix
Before attempting to delete the PortableGit directory, the code should:
- Kill any running
git.exeprocesses that originate from the SM library directory. - Strip read-only attributes recursively as a safety net.
Example:
if (Directory.Exists(PortableGitInstallDir))
{
// Kill any git processes that may have the executable locked
foreach (var proc in Process.GetProcessesByName("git"))
{
try
{
if (proc.MainModule?.FileName.StartsWith(PortableGitInstallDir, StringComparison.OrdinalIgnoreCase) == true)
{
proc.Kill(entireProcessTree: true);
await proc.WaitForExitAsync();
}
}
catch (Exception ex)
{
Logger.Warn(ex, "Failed to kill git process before upgrade");
}
}
// Strip read-only attributes recursively before deletion
foreach (var file in Directory.EnumerateFiles(PortableGitInstallDir, "*", SearchOption.AllDirectories))
{
try { File.SetAttributes(file, File.GetAttributes(file) & ~FileAttributes.ReadOnly); }
catch { /* ignore */ }
}
await new DirectoryPath(PortableGitInstallDir).DeleteAsync(true);
}Workaround
Manually delete the PortableGit folder from the Stability Matrix library directory while the application is closed, then reopen Stability Matrix to trigger a fresh Git installation.
Environment
- Platform: Windows
- Component:
WindowsPrerequisiteHelper.InstallGitIfNecessary - Triggered by: Git version upgrade check in Settings → Run Git Process