{"record":{"id":"f23592137f56b4b7","repo":"QL-Win/QuickLook","slug":"folder-is-not-writable","errorCode":null,"errorMessage":"{folder} is not writable.","messagePattern":"(.+?) is not writable\\.","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":null,"severity":"error","filePath":"QuickLook.Common/Helpers/FileHelper.cs","lineNumber":63,"sourceCode":"\n    public static string CreateTempFile(string folder, string filename = null)\n    {\n        if (string.IsNullOrWhiteSpace(filename))\n            filename = Guid.NewGuid() + \".tmp\";\n        var fullPath = Path.Combine(folder, filename);\n\n        var handle = new SafeFileHandle(IntPtr.Zero, true);\n\n        try\n        {\n            Directory.CreateDirectory(folder);\n\n            handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,\n                FileShare.None,\n                IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);\n\n            if (handle.IsInvalid)\n                throw new UnauthorizedAccessException($\"{folder} is not writable.\");\n\n            return fullPath;\n        }\n        finally\n        {\n            if (!handle.IsInvalid && !handle.IsClosed)\n                handle.Close();\n        }\n    }\n\n    public static bool GetAssocApplication(string path, out string appFriendlyName)\n    {\n        appFriendlyName = string.Empty;\n        var ext = Path.GetExtension(path).ToLower();\n\n        // no assoc. app. found\n        if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command)))\n            if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/QL-Win/QuickLook/blob/cb5d9c429c81d9796fac469da2a68efb5626946d/QuickLook.Common/Helpers/FileHelper.cs#L45-L81","documentation":"Thrown by FileHelper.CreateTempFile when NativeMethods.Kernel32.CreateFile returns an invalid handle (INVALID_HANDLE_VALUE) for the target path under {folder}. Despite the UnauthorizedAccessException type, the real Win32 cause can be access denied, path-not-found, invalid path characters, or disk full — the code never calls Marshal.GetLastWin32Error to disambiguate. The interpolated message names only the folder, not the file or the underlying error code.","triggerScenarios":"Calling FileHelper.CreateTempFile(folder, filename) where CreateFile with FileMode.Create / FileAttributes.Temporary fails: folder is on read-only media, the process lacks write ACL on the directory, the path exceeds MAX_PATH, an antivirus blocks creation, or the disk is full.","commonSituations":"QuickLook runs under a restricted context (e.g. preview hosted by explorer.exe or a low-integrity process); the temp folder is redirected to a protected location; a group policy locks down %TEMP%; a path with Unicode or very long segments exceeds 260 chars; AV/EDR hooks block the CreateFile call.","solutions":["Verify the folder is writable by the current process (Directory.CreateDirectory then attempt a test write) before calling CreateTempFile.","Call Marshal.GetLastWin32Error right after CreateFile to surface the real Win32 error code and map it to a precise message.","Fall back to Path.GetTempPath() (the system %TEMP%) when the supplied folder is not writable.","Ensure the folder path stays under MAX_PATH or enable long-path support; sanitize filename for invalid characters.","Check available disk space on the target drive before creating temp files."],"exampleFix":"// before\nhandle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,\n    FileShare.None, IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);\nif (handle.IsInvalid)\n    throw new UnauthorizedAccessException($\"{folder} is not writable.\");\n\n// after\nhandle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,\n    FileShare.None, IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);\nif (handle.IsInvalid)\n{\n    int err = Marshal.GetLastWin32Error();\n    throw new UnauthorizedAccessException(\n        $\"{folder} is not writable (Win32 error {err}: {new System.ComponentModel.Win32Exception(err).Message}).\");\n}","handlingStrategy":"validation","validationCode":"// Validate the folder is writable before calling CreateTempFile.\npublic static bool IsFolderWritable(string folder)\n{\n    try\n    {\n        Directory.CreateDirectory(folder);\n        string probe = Path.Combine(folder, $\".writeprobe_{Guid.NewGuid():N}\");\n        File.WriteAllText(probe, \"x\");\n        File.Delete(probe);\n        return true;\n    }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { var path = FileHelper.CreateTempFile(folder); }\ncatch (UnauthorizedAccessException ex)\n{\n    // folder lacks write permission or CreateFile failed;\n    // fall back to system temp: Path.GetTempPath()\n    logger.Warn(ex, $\"Folder {folder} not writable, using system temp.\");\n    path = FileHelper.CreateTempFile(Path.GetTempPath());\n}","preventionTips":["Prefer Path.GetTempPath() for temp files unless a specific folder is required.","Check Directory.Exists / writability before passing a custom folder.","Keep paths under MAX_PATH and sanitize for invalid characters.","Ensure the process runs with sufficient ACL/privilege on the target directory."],"tags":["io","windows-native","permissions","temp-file","csharp"],"backgroundTag":null,"analyzedSha":"cb5d9c429c81d9796fac469da2a68efb5626946d","analyzedAt":"2026-08-13T11:51:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}