{"record":{"id":"50fa4da85e7674eb","repo":"LykosAI/StabilityMatrix","slug":"unable-to-delete-junction-point","errorCode":null,"errorMessage":"Unable to delete junction point.","messagePattern":"Unable to delete junction point\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"StabilityMatrix.Core/ReparsePoints/Junction.cs","lineNumber":160,"sourceCode":"            Debug.WriteLine($\"bytesReturned: {bytesReturned}\");\n            \n            if (!result)\n            {\n                ThrowLastWin32Error($\"Unable to delete junction point {junctionPoint}\");\n            }\n        }\n        finally\n        {\n            Marshal.FreeHGlobal(inBuffer);\n        }\n\n        try\n        {\n            Directory.Delete(junctionPoint);\n        }\n        catch (IOException ex)\n        {\n            throw new IOException(\"Unable to delete junction point.\", ex);\n        }\n    }\n    \n    /// <summary>\n    /// Determines whether the specified path exists and refers to a junction point.\n    /// </summary>\n    /// <param name=\"path\">The junction point path</param>\n    /// <returns>True if the specified path represents a junction point</returns>\n    /// <exception cref=\"IOException\">Thrown if the specified path is invalid\n    /// or some other error occurs</exception>\n    public static bool Exists(string path)\n    {\n        if (!Directory.Exists(path)) return false;\n\n        using var handle = OpenReparsePoint(path, Win32FileAccess.GenericRead);\n        var target = InternalGetTarget(handle);\n        return target != null;\n    }","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/LykosAI/StabilityMatrix/blob/af93d6ef57c01cd890d7e0ad0a9ea8c9fcda3002/StabilityMatrix.Core/ReparsePoints/Junction.cs#L142-L178","documentation":"Delete() first removes the reparse point via DeviceIoControl, then calls Directory.Delete(junctionPoint). If the final Directory.Delete throws IOException (directory not empty, locked, or on a deleted target), the method wraps it in this IOException. It means the junction reparse data was removed but the now-plain directory itself could not be deleted.","triggerScenarios":"Calling Junction.Delete on a path whose underlying directory contains files placed inside it after the junction was created, or where the directory handle is held open by another process, or where the target was removed concurrently so the directory state is inconsistent.","commonSituations":"Deleting a shared-models junction while an app (e.g. ComfyUI) still has files open inside it; antivirus or an indexer holding the directory; a partially-failed previous Delete attempt leaving a plain non-empty directory; running on a network drive where reparse deletion half-completed.","solutions":["Check that the directory under the junction path is actually empty (e.g. Directory.EnumerateFileSystemEntries) before calling Delete; move out or delete any contents","Close any process holding handles inside the junction (apps, editors, antivirus scans) and retry","Call Junction.Exists(path) first to confirm it is still a junction; if the reparse point was already removed, use Directory.Delete directly","Catch IOException, inspect the inner exception, and clean up the leftover empty/plain directory manually"],"exampleFix":"// before\nJunction.Delete(path); // IOException if dir not empty\n// after\nif (Junction.Exists(path))\n{\n    foreach (var f in Directory.EnumerateFileSystemEntries(path))\n        throw new IOException($\"Junction target not empty: {f}\");\n    Junction.Delete(path);\n}\nelse\n{\n    Directory.Delete(path, recursive: true);\n}","handlingStrategy":"try-catch","validationCode":"if (!Directory.Exists(path)) throw new FileNotFoundException(path);\nbool isJunction = Junction.Exists(path);\nbool empty = !Directory.EnumerateFileSystemEntries(path).Any();\nif (!isJunction || !empty) throw new InvalidOperationException(\"Path must be an empty junction point.\");","typeGuard":"static bool IsDeletableJunction(string path) =>\n    Directory.Exists(path) && Junction.Exists(path) && !Directory.EnumerateFileSystemEntries(path).Any();","tryCatchPattern":"try\n{\n    Junction.Delete(path);\n}\ncatch (IOException ex)\n{\n    // inner exception tells whether dir was locked/not empty\n    logger.LogError(ex.InnerException ?? ex, \"Failed to delete junction {Path}\", path);\n    if (Directory.Exists(path) && !Junction.Exists(path))\n        Directory.Delete(path, recursive: false); // reparse already removed\n}","preventionTips":["Always call Junction.Exists before Delete","Ensure no apps/services hold files under the junction (close editors, pause AV scans)","Empty the junction's contents before deleting","Handle the leftover-directory case: after a failed delete, check whether the reparse point is already gone and clean up with Directory.Delete"],"tags":["filesystem","junction","windows","io"],"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"}