dotnet/efcore · error · InvalidOperationException

The indexes {index1} on '{entityType1}' and {index2} on '{en

Error message

The indexes {index1} on '{entityType1}' and {index2} on '{entityType2}' are both mapped to '{table}.{indexName}', but with different sort orders.

What it means

Thrown by RelationalIndexExtensions.AreCompatible when two same-named indexes on the same table have matching columns and uniqueness but disagree on descending sort order (IsDescending). A physical index has one collation/sort, so EF rejects conflicting IsDescending configurations under one name.

Source

Thrown at src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs:99

        }

        return index.IsUnique != duplicateIndex.IsUnique
            ? shouldThrow
                ? throw new InvalidOperationException(
                    RelationalStrings.DuplicateIndexUniquenessMismatch(
                        index.DisplayName(),
                        index.DeclaringEntityType.DisplayName(),
                        duplicateIndex.DisplayName(),
                        duplicateIndex.DeclaringEntityType.DisplayName(),
                        index.DeclaringEntityType.GetSchemaQualifiedTableName(),
                        index.GetDatabaseName(storeObject)))
                : false
            : (index.IsDescending is null) != (duplicateIndex.IsDescending is null)
            || (index.IsDescending is not null
                && duplicateIndex.IsDescending is not null
                && !index.IsDescending.SequenceEqual(duplicateIndex.IsDescending))
                ? shouldThrow
                    ? throw new InvalidOperationException(
                        RelationalStrings.DuplicateIndexSortOrdersMismatch(
                            index.DisplayName(),
                            index.DeclaringEntityType.DisplayName(),
                            duplicateIndex.DisplayName(),
                            duplicateIndex.DeclaringEntityType.DisplayName(),
                            index.DeclaringEntityType.GetSchemaQualifiedTableName(),
                            index.GetDatabaseName(storeObject)))
                    : false
                : index.GetFilter(storeObject) == duplicateIndex.GetFilter(storeObject)
                || (shouldThrow
                    ? throw new InvalidOperationException(
                        RelationalStrings.DuplicateIndexFiltersMismatch(
                            index.DisplayName(),
                            index.DeclaringEntityType.DisplayName(),
                            duplicateIndex.DisplayName(),
                            duplicateIndex.DeclaringEntityType.DisplayName(),
                            index.DeclaringEntityType.GetSchemaQualifiedTableName(),
                            index.GetDatabaseName(storeObject),

View on GitHub (pinned to dbf9771522)

Solutions

  1. Apply the same IsDescending(...) array/value on every index sharing the database name.
  2. If sort orders genuinely differ, rename one index with HasDatabaseName.
  3. Remove the second IsDescending call so both fall back to the default ascending order.

Example fix

// before
modelBuilder.Entity<A>().HasIndex(a => new { a.Tenant, a.Name }).IsDescending().HasDatabaseName("IX_TN");
modelBuilder.Entity<B>().HasIndex(b => new { b.Tenant, b.Name }).IsDescending(false).HasDatabaseName("IX_TN"); // throws

// after
modelBuilder.Entity<B>().HasIndex(b => new { b.Tenant, b.Name }).IsDescending().HasDatabaseName("IX_TN");
Defensive patterns

Strategy: validation

Validate before calling

// Detect IsDescending mismatches for colliding index names
var conflicts = model.GetEntityTypes()
    .SelectMany(e => e.GetDeclaredIndexes())
    .Where(i => i.GetDatabaseName() != null)
    .GroupBy(i => i.GetDatabaseName())
    .Where(g => g.Select(i => i.IsDescending == null ? "" : string.Join(",", i.IsDescending)).Distinct().Count() > 1);
if (conflicts.Any()) throw new InvalidOperationException("Sort-order mismatch on shared indexes.");

Prevention

When it happens

Trigger: Lines 94-107: one index has IsDescending null while the other is set, or both are non-null but not SequenceEqual. Produced by calling IsDescending()/IsDescending(true) on one HasIndex and IsDescending(false) (or nothing) on the colliding one.

Common situations: Table sharing where one entity uses IsDescending() for descending and the other uses ascending; EF8+ descending-index support added to one entity but not its table-sharing peer; index on composite key where only part of the order differs.

Related errors


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