dotnet/efcore · error · InvalidOperationException

Azure Cosmos DB does not support synchronous I/O. Make sure

Error message

Azure Cosmos DB does not support synchronous I/O. Make sure to use and correctly await only async methods when using Entity Framework Core to access Azure Cosmos DB.

What it means

The synchronous SaveChanges() override (CosmosDatabaseWrapper.cs:628-629) unconditionally throws because all Cosmos DB write operations (create, replace, delete) are asynchronous via the Microsoft.Azure.Cosmos SDK. There is no synchronous write path. This prevents deadlocks from sync-over-async wrapping.

Source

Thrown at src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseWrapper.cs:629

    private sealed class CosmosUpdateEntry
    {
        public required IUpdateEntry Entry { get; init; }
        public required CosmosCudOperation Operation { get; init; }
        public required string CollectionId { get; init; }
        public required CosmosStructuralTypeSerializer Serializer { get; init; }
    }

    private sealed record Grouping(string ContainerId, PartitionKey PartitionKeyValue);

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public override int SaveChanges(IList<IUpdateEntry> entries)
        => throw new InvalidOperationException(CosmosStrings.SyncNotSupported);
}

View on GitHub (pinned to dbf9771522)

Solutions

  1. Use the async overload: await context.SaveChangesAsync().
  2. Make all repository/service methods async Task and propagate await up the call stack.
  3. Refactor sync callers to async; avoid .GetAwaiter().GetResult() or .Result which can deadlock.

Example fix

// before
public void Save(Blog blog)
{
    _context.Blogs.Add(blog);
    _context.SaveChanges();
}

// after
public async Task SaveAsync(Blog blog)
{
    _context.Blogs.Add(blog);
    await _context.SaveChangesAsync();
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure SaveChangesAsync is used. Enforce via async repository patterns.
if (context.Database.ProviderName == "Microsoft.EntityFrameworkCore.Cosmos")
{
    // always: await context.SaveChangesAsync();
}

Prevention

When it happens

Trigger: Calling context.SaveChanges() (without Async) on a Cosmos-backed DbContext. This directly throws before any entries are processed.

Common situations: Calling SaveChanges from synchronous application code, legacy libraries, or property setters. Copy-pasting relational save patterns. Using a shared repository abstraction with a sync Save method.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/ec8782675dc55cd7. Report an issue: GitHub.