{"record":{"id":"ae7030c7bd72a5b4","repo":"dotnet/efcore","slug":"the-indexes-index1-on-entitytype1-and-index-ae7030","errorCode":null,"errorMessage":"The indexes {index1} on '{entityType1}' and {index2} on '{entityType2}' are both mapped to '{table}.{indexName}', but with different filters ('{filter1}' and '{filter2}').","messagePattern":"The indexes (.+?) on '(.+?)' and (.+?) on '(.+?)' are both mapped to '(.+?)\\.(.+?)', but with different filters \\('(.+?)' and '(.+?)'\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs","lineNumber":110,"sourceCode":"                        index.GetDatabaseName(storeObject)))\n                : false\n            : (index.IsDescending is null) != (duplicateIndex.IsDescending is null)\n            || (index.IsDescending is not null\n                && duplicateIndex.IsDescending is not null\n                && !index.IsDescending.SequenceEqual(duplicateIndex.IsDescending))\n                ? shouldThrow\n                    ? throw new InvalidOperationException(\n                        RelationalStrings.DuplicateIndexSortOrdersMismatch(\n                            index.DisplayName(),\n                            index.DeclaringEntityType.DisplayName(),\n                            duplicateIndex.DisplayName(),\n                            duplicateIndex.DeclaringEntityType.DisplayName(),\n                            index.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                            index.GetDatabaseName(storeObject)))\n                    : false\n                : index.GetFilter(storeObject) == duplicateIndex.GetFilter(storeObject)\n                || (shouldThrow\n                    ? throw new InvalidOperationException(\n                        RelationalStrings.DuplicateIndexFiltersMismatch(\n                            index.DisplayName(),\n                            index.DeclaringEntityType.DisplayName(),\n                            duplicateIndex.DisplayName(),\n                            duplicateIndex.DeclaringEntityType.DisplayName(),\n                            index.DeclaringEntityType.GetSchemaQualifiedTableName(),\n                            index.GetDatabaseName(storeObject),\n                            index.GetFilter(),\n                            duplicateIndex.GetFilter()))\n                    : false);\n    }\n\n    private static string FormatColumnNames(IEnumerable<string> columnNames)\n        => \"{\" + string.Join(\", \", columnNames.Select(n => \"'\" + n + \"'\")) + \"}\";\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs#L92-L128","documentation":"Two indexes share the same database name and table but have different filter expressions (e.g. WHERE clauses on partial/filtered indexes). A single database index can only carry one filter.","triggerScenarios":"RelationalIndexExtensions.AreCompatible with shouldThrow:true when index.GetFilter(storeObject) != duplicateIndex.GetFilter(storeObject). Happens when HasIndex(...).HasFilter(...) is used inconsistently on two indexes that resolve to the same database name.","commonSituations":"Filtered indexes on SQL Server/PostgreSQL with colliding names; table-splitting where one entity wants a partial index and another does not; legacy migrations with manually edited filter strings.","solutions":["Use identical HasFilter expressions on both indexes.","Give the indexes distinct database names via HasDatabaseName so each can have its own filter.","Remove one of the indexes if it is redundant.","If no filter is intended, ensure neither index sets HasFilter."],"exampleFix":"// before\nmodelBuilder.Entity<User>().HasIndex(u => u.Email)\n    .HasFilter(\"[Email] IS NOT NULL\").HasDatabaseName(\"IX_User_Email\");\nmodelBuilder.Entity<DeletedUser>().ToTable(\"User\").HasIndex(u => u.Email)\n    .HasFilter(\"[Email] IS NULL\").HasDatabaseName(\"IX_User_Email\");\n\n// after: distinct names so each filter is independent\nmodelBuilder.Entity<DeletedUser>().ToTable(\"User\").HasIndex(u => u.Email)\n    .HasFilter(\"[Email] IS NULL\").HasDatabaseName(\"IX_User_Email_Deleted\");","handlingStrategy":"validation","validationCode":"// Detect filter mismatches for colliding index names.\nvar groups = modelBuilder.Model.GetEntityTypes()\n    .SelectMany(e => e.GetDeclaredIndexes())\n    .GroupBy(i => new { Name = i.GetDatabaseName(), Table = i.DeclaringEntityType.GetSchemaQualifiedTableName() })\n    .Where(g => g.Count() > 1);\nforeach (var g in groups)\n{\n    var filters = g.Select(i => i.GetFilter() ?? string.Empty).Distinct();\n    if (filters.Count() > 1)\n        Console.WriteLine($\"Index '{g.Key.Name}' has conflicting filters: {string.Join(\" | \", filters)}.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When using HasFilter, ensure all indexes sharing a database name use the same filter or assign distinct names.","Prefer distinct HasDatabaseName for filtered indexes from the start.","Validate the model in CI."],"tags":["ef-core","relational-metadata","index","filtered-index","model-validation"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}