abpframework/abp · error · BlobAlreadyExistsException

Saving BLOB '{args.BlobName}' does already exists in the con

Error message

Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set OverrideExisting if it should be overwritten.

What it means

Thrown by FileSystemBlobProvider.SaveAsync when OverrideExisting is false and a file already exists at the calculated file path (ExistsAsync returns true). It is the filesystem analogue of the cloud providers' BlobAlreadyExistsException, guarding against silent overwrites before DirectoryHelper creates the directory and the file is opened with FileMode.CreateNew.

Source

Thrown at framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobProvider.cs:25

namespace Volo.Abp.BlobStoring.FileSystem;

public class FileSystemBlobProvider : BlobProviderBase, ITransientDependency
{
    protected IBlobFilePathCalculator FilePathCalculator { get; }

    public FileSystemBlobProvider(IBlobFilePathCalculator filePathCalculator)
    {
        FilePathCalculator = filePathCalculator;
    }

    public override async Task SaveAsync(BlobProviderSaveArgs args)
    {
        var filePath = FilePathCalculator.Calculate(args);

        if (!args.OverrideExisting && await ExistsAsync(filePath))
        {
            throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten.");
        }

        DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(filePath)!);

        var fileMode = args.OverrideExisting
            ? FileMode.Create
            : FileMode.CreateNew;

        // A failure is only retried while it is replayable: before OpenFileStream returns
        // (the source is untouched), or for a seekable overwrite (the source can seek back
        // and FileMode.Create truncates the partial content). Otherwise a retry would
        // replay a half-consumed source or hit the file a failed CreateNew attempt left behind.
        long sourcePosition;
        try
        {
            sourcePosition = args.BlobStream.CanSeek && fileMode == FileMode.Create ? args.BlobStream.Position : -1;
        }
        catch (Exception ex) when (ex is NotSupportedException || ex is IOException)

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Pass overrideExisting: true to replace the existing file (the provider then uses FileMode.Create).
  2. Use a unique blob/file name per save.
  3. Call ExistsAsync first and branch.
  4. Delete the existing file before re-saving if overwrite semantics are unwanted.

Example fix

// before
await container.SaveAsync("data.bin", stream);

// after
await container.SaveAsync("data.bin", stream, overrideExisting: true);
Defensive patterns

Strategy: validation

Validate before calling

if (await container.ExistsAsync(blobName))
{
    await container.SaveAsync(blobName, stream, overrideExisting: true);
    return;
}
await container.SaveAsync(blobName, stream);

Type guard

bool willConflict = !args.OverrideExisting && await container.ExistsAsync(blobName);

Try / catch

try { await container.SaveAsync(blobName, stream); }
catch (BlobAlreadyExistsException)
{ /* rename or retry with overrideExisting: true */ }

Prevention

When it happens

Trigger: Saving a blob through the FileSystem provider where the file at FilePathCalculator.Calculate(args) already exists and OverrideExisting is false. The existence check uses File.Exists on the resolved path.

Common situations: Re-saving a file under a stable path, retrying a write that completed, persistent local storage where keys collide, or multiple app instances writing to a shared filesystem path.

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/9b47e92daaa78cf2. Report an issue: GitHub.