QL-Win/QuickLook · error · UnauthorizedAccessException

is not writable.

Error message

{folder} is not writable.

What it means

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.

Solutions

  1. Verify the folder is writable by the current process (Directory.CreateDirectory then attempt a test write) before calling CreateTempFile.
  2. Call Marshal.GetLastWin32Error right after CreateFile to surface the real Win32 error code and map it to a precise message.
  3. Fall back to Path.GetTempPath() (the system %TEMP%) when the supplied folder is not writable.
  4. Ensure the folder path stays under MAX_PATH or enable long-path support; sanitize filename for invalid characters.
  5. Check available disk space on the target drive before creating temp files.

Example fix

// before
handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,
    FileShare.None, IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);
if (handle.IsInvalid)
    throw new UnauthorizedAccessException($"{folder} is not writable.");

// after
handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,
    FileShare.None, IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);
if (handle.IsInvalid)
{
    int err = Marshal.GetLastWin32Error();
    throw new UnauthorizedAccessException(
        $"{folder} is not writable (Win32 error {err}: {new System.ComponentModel.Win32Exception(err).Message}).");
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the folder is writable before calling CreateTempFile.
public static bool IsFolderWritable(string folder)
{
    try
    {
        Directory.CreateDirectory(folder);
        string probe = Path.Combine(folder, $".writeprobe_{Guid.NewGuid():N}");
        File.WriteAllText(probe, "x");
        File.Delete(probe);
        return true;
    }
    catch { return false; }
}

Try / catch

try { var path = FileHelper.CreateTempFile(folder); }
catch (UnauthorizedAccessException ex)
{
    // folder lacks write permission or CreateFile failed;
    // fall back to system temp: Path.GetTempPath()
    logger.Warn(ex, $"Folder {folder} not writable, using system temp.");
    path = FileHelper.CreateTempFile(Path.GetTempPath());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of QL-Win/QuickLook@cb5d9c429c (2026-08-13). Data as JSON: /api/errors/f23592137f56b4b7. Report an issue: GitHub.

Appendix: source

Thrown at QuickLook.Common/Helpers/FileHelper.cs:63

    public static string CreateTempFile(string folder, string filename = null)
    {
        if (string.IsNullOrWhiteSpace(filename))
            filename = Guid.NewGuid() + ".tmp";
        var fullPath = Path.Combine(folder, filename);

        var handle = new SafeFileHandle(IntPtr.Zero, true);

        try
        {
            Directory.CreateDirectory(folder);

            handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,
                FileShare.None,
                IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);

            if (handle.IsInvalid)
                throw new UnauthorizedAccessException($"{folder} is not writable.");

            return fullPath;
        }
        finally
        {
            if (!handle.IsInvalid && !handle.IsClosed)
                handle.Close();
        }
    }

    public static bool GetAssocApplication(string path, out string appFriendlyName)
    {
        appFriendlyName = string.Empty;
        var ext = Path.GetExtension(path).ToLower();

        // no assoc. app. found
        if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command)))
            if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP

View on GitHub (pinned to cb5d9c429c)