Radarr/Radarr · error · IOException

Source and destination can't be the same {0}

Error message

Source and destination can't be the same {0}

What it means

CloneFile refuses to operate when source.PathEquals(destination). Cloning a file onto itself would be a destructive no-op, so an IOException is thrown. PathEquals normalizes case per OS rules, so on Windows a case-only difference may also trip this.

Source

Thrown at src/NzbDrone.Common/Disk/DiskProviderBase.cs:238

        public void DeleteFile(string path)
        {
            Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
            Logger.Trace("Deleting file: {0}", path);

            RemoveReadOnly(path);

            File.Delete(path);
        }

        public void CloneFile(string source, string destination, bool overwrite = false)
        {
            Ensure.That(source, () => source).IsValidPath(PathValidationType.CurrentOs);
            Ensure.That(destination, () => destination).IsValidPath(PathValidationType.CurrentOs);

            if (source.PathEquals(destination))
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", source));
            }

            CloneFileInternal(source, destination, overwrite);
        }

        protected virtual void CloneFileInternal(string source, string destination, bool overwrite = false)
        {
            CopyFileInternal(source, destination, overwrite);
        }

        public void CopyFile(string source, string destination, bool overwrite = false)
        {
            Ensure.That(source, () => source).IsValidPath(PathValidationType.CurrentOs);
            Ensure.That(destination, () => destination).IsValidPath(PathValidationType.CurrentOs);

            if (source.PathEquals(destination))
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", source));

View on GitHub (pinned to ca451608dc)

Solutions

  1. Normalize both paths with Path.GetFullPath and compare before calling — skip if equal
  2. For case-only renames on case-insensitive FS, rename via a temporary intermediate name
  3. Fix the caller that produced equal source and destination
  4. If the no-op is expected, short-circuit and return success instead of calling CloneFile

Example fix

// before
_diskProvider.CloneFile(source, destination);

// after
if (Path.GetFullPath(source) == Path.GetFullPath(destination))
{
    return; // already at target
}
_diskProvider.CloneFile(source, destination);
Defensive patterns

Strategy: validation

Validate before calling

if (Path.GetFullPath(source) == Path.GetFullPath(destination))
{
    return; // no-op clone, skip
}

Try / catch

try
{
    _diskProvider.CloneFile(source, destination, overwrite);
}
catch (IOException ex) when (ex.Message.Contains("can't be the same"))
{
    // source == destination; treat as success
}

Prevention

When it happens

Trigger: Caller computes a destination that resolves to the same path as the source; case-only rename on a case-insensitive filesystem where PathEquals already treats them as equal; bug in path-joining logic producing target == source.

Common situations: Episode already at the desired path so the clone target equals source; renaming routine that does not short-circuit the no-op case; Windows case-only rename attempts.

Related errors


AI-assisted analysis of Radarr/Radarr@ca451608dc (2026-08-13). Data as JSON: /api/errors/faf42ebe405249cd. Report an issue: GitHub.