{"record":{"id":"a3b3fa9e6d688a40","repo":"LykosAI/StabilityMatrix","slug":"failed-to-delete-file-filepath","errorCode":null,"errorMessage":"Failed to delete file {filePath}","messagePattern":"Failed to delete file (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"StabilityMatrix/ViewModels/PackageManagerViewModel.cs","lineNumber":266,"sourceCode":"        }\n        // Recursively delete all subdirectories\n        var subdirectoryEntries = Directory.GetDirectories(targetDirectory);\n        foreach (var subdirectoryPath in subdirectoryEntries)\n        {\n            DeleteDirectory(subdirectoryPath);\n        }\n        // Delete all files in the directory\n        var fileEntries = Directory.GetFiles(targetDirectory);\n        foreach (var filePath in fileEntries)\n        {\n            try\n            {\n                File.SetAttributes(filePath, FileAttributes.Normal);\n                File.Delete(filePath);\n            }\n            catch (IOException ex)\n            {\n                throw new IOException($\"Failed to delete file {filePath}\", ex);\n            }\n        }\n        // Delete the target directory itself\n        try\n        {\n            Directory.Delete(targetDirectory, false);\n        }\n        catch (IOException ex)\n        {\n            throw new IOException($\"Failed to delete directory {targetDirectory}\", ex);\n        }\n    }\n\n    private async Task UpdateSelectedPackage()\n    {\n        var package = packageFactory.FindPackageByName(SelectedPackage?.PackageName ?? string.Empty);\n        if (package == null)\n        {","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/LykosAI/StabilityMatrix/blob/af93d6ef57c01cd890d7e0ad0a9ea8c9fcda3002/StabilityMatrix/ViewModels/PackageManagerViewModel.cs#L248-L284","documentation":"This IOException is thrown by PackageManagerViewModel.DeleteDirectory when an individual file inside the package directory cannot be deleted. The routine clears file attributes (File.SetAttributes to Normal, to strip ReadOnly/Hidden) and then calls File.Delete; if the OS refuses with an IOException, the file path is wrapped in this message. The async caller retries up to 3 times with exponential backoff via Polly because deletions typically fail transiently when another process still holds an open handle.","triggerScenarios":"File.Delete(filePath) throws IOException while recursively deleting a package directory: the file is locked/open in another process (running package executable, console window, editor, antivirus scanner), the file is on a network/synced drive (OneDrive/Dropbox placeholder), the disk is full or the media is write-protected, or clearing attributes with File.SetAttributes itself fails on inaccessible storage.","commonSituations":"Deleting a ComfyUI/A1111 package while its server process is still running and has python files or model checkpoints open; a shared venv or model file being scanned by Windows Defender; the package lives in a OneDrive 'cloud files' folder where hydration makes Delete fail; a long path (>260 chars) deep in a package tree.","solutions":["Stop every process using the package (the package server/venv, editors, terminals) and retry the delete.","Check the inner exception's HResult to identify the cause: 0x80070020 (sharing violation) means a process holds the file; 0x80070005 means access denied; 0x8007108D means the file is a cloud placeholder.","Exclude the Stability Matrix packages folder from antivirus/backup/OneDrive sync and retry.","Ensure the drive is not read-only or full, and check file permissions/ownership on the package directory.","If retries keep failing, reboot (releases leaked handles) and delete the package again, or remove it manually in Explorer."],"exampleFix":"// caller: stop processes before deleting, and surface the inner exception for diagnosis\ntry\n{\n    await StopPackageProcesses(); // kill running package server before delete\n    await DeleteDirectoryAsync(packagePath);\n}\ncatch (IOException ex)\n{\n    logger.LogError(ex, \"Could not delete {File}: {Reason}\", ex.Message, ex.InnerException?.HResult);\n    NotifyUser(\"Close programs using this package and try again.\");\n}","handlingStrategy":"try-catch","validationCode":"if (!Directory.Exists(packagePath)) return;\n// best-effort pre-check: no file in the tree is currently open for write\nforeach (var f in Directory.EnumerateFiles(packagePath, \"*\", SearchOption.AllDirectories))\n{\n    try { using var fs = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.None); }\n    catch (IOException) { throw new InvalidOperationException($\"File is in use: {f}\"); }\n}","typeGuard":"static bool IsDeletableFile(string path) =>\n    File.Exists(path) && !new FileInfo(path).Attributes.HasFlag(FileAttributes.ReparsePoint);","tryCatchPattern":"try\n{\n    await DeleteDirectoryAsync(packagePath);\n}\ncatch (IOException ex)\n{\n    var hresult = ex.InnerException?.HResult;\n    if (hresult == unchecked((int)0x80070020))\n        NotifyUser(\"A file is open in another program. Close it and retry.\");\n    else if (hresult == unchecked((int)0x80070005))\n        NotifyUser(\"Access denied. Run as admin or fix folder permissions.\");\n    else\n        logger.LogError(ex, \"Failed to delete {Path}\", packagePath);\n}","preventionTips":["Always stop the package process and wait for exit before deleting its directory.","Keep packages outside OneDrive/Dropbox/synced or network folders.","Exclude the packages directory from antivirus real-time scanning.","Catch IOException and inspect HResult instead of assuming deletion succeeded.","Keep paths short (avoid deeply nested venvs) to dodge long-path failures on Windows."],"tags":["file-io","windows","file-locked","ioexception"],"backgroundTag":"file-delete-failed","analyzedSha":"af93d6ef57c01cd890d7e0ad0a9ea8c9fcda3002","analyzedAt":"2026-09-12T19:02:43.389Z","contentChangedAt":"2026-09-12T19:02:43.389Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}