d2phap/ImageGlass · error · IOException

IGE: could not finalize '{destFilePath}'. {moveError}

Error message

IGE: could not finalize '{destFilePath}'. {moveError}

What it means

Thrown by CodecEncodePipeline.TryEncodeAsync when the plugin encode to a temp staging file (.ig-save-*) succeeded but File.Move onto the real destination failed. TryPromote reports the underlying exception message instead of throwing directly, so the pipeline wraps it as IOException. The temp file is deleted best-effort on every failure path.

Source

Thrown at source/ImageGlass.Lib/Common/Photoing/Codecs/Registry/CodecEncodePipeline.cs:84

                ? await EncodeMultiFrameAsync(codec, photo, tempPath, transform, quality, token).ConfigureAwait(false)
                : await EncodeSingleFrameAsync(codec, photo, tempPath, transform, quality, token).ConfigureAwait(false);

            if (result.Unsupported)
            {
                TryDelete(tempPath);
                return false;
            }
            if (!result.Succeeded)
            {
                TryDelete(tempPath);
                throw new InvalidDataException(
                    $"IGE: '{codec.CodecName}' could not write the image. {result.Error}".TrimEnd());
            }

            if (!TryPromote(tempPath, destFilePath, out var moveError))
            {
                TryDelete(tempPath);
                throw new IOException($"IGE: could not finalize '{destFilePath}'. {moveError}".TrimEnd());
            }

            return true;
        }
        catch (OperationCanceledException)
        {
            TryDelete(tempPath);
            throw;
        }
        catch
        {
            TryDelete(tempPath);
            throw;
        }
    }


    /// <summary>

View on GitHub (pinned to 4a3c4fecef)

Solutions

  1. Close any other application that may hold the destination file open, then retry.
  2. Save to a writable temporary location first, then copy/move once the lock is released.
  3. Verify write permission and free disk space on the destination folder.
  4. For cloud-sync folders, pause sync or save outside the sync root and move manually.

Example fix

// before
await photo.SaveAsAsync(destFilePath, transform, quality, token);

// after
try
{
    await photo.SaveAsAsync(destFilePath, transform, quality, token);
}
catch (IOException ex) when (ex.Message.Contains("could not finalize"))
{
    var tmp = Path.Combine(Path.GetTempPath(), Path.GetFileName(destFilePath));
    await photo.SaveAsAsync(tmp, transform, quality, token);
    File.Copy(tmp, destFilePath, overwrite: true);
}
Defensive patterns

Strategy: retry

Validate before calling

var dir = Path.GetDirectoryName(destFilePath);
if (!Directory.Exists(dir) || !HasWriteAccess(dir))
    throw new InvalidOperationException("Destination folder is not writable.");
bool HasWriteAccess(string p) { try { var f = Path.Combine(p, $".ig-probe-{Guid.NewGuid():N}"); File.WriteAllText(f, ""); File.Delete(f); return true; } catch { return false; } }

Try / catch

try { await photo.SaveAsAsync(destFilePath, transform, quality, token); }
catch (IOException ex) when (ex.Message.Contains("could not finalize"))
{ await Task.Delay(250); /* retry once, or save to temp then copy */ }

Prevention

When it happens

Trigger: Destination file is locked by another process (image editor, viewer, cloud-sync client, antivirus); destination folder is read-only or the user lacks permission; destination disk is full; destination path is invalid or on an unwritable network share.

Common situations: Saving over a file currently being uploaded by OneDrive/Dropbox/Google Drive; saving into a protected system directory; disk full mid-write; antivirus scanning the new file and holding a brief lock.

Related errors


AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13). Data as JSON: /api/errors/9fd21d7cf8664653. Report an issue: GitHub.