{"record":{"id":"567b2283ec143045","repo":"dotnet/efcore","slug":"the-index-indexproperties-on-the-entity-type-e-567b22","errorCode":null,"errorMessage":"The index {indexProperties} on the entity type '{entityType}' cannot be configured because its properties are mapped to different JSON columns ('{firstColumn}' and '{secondColumn}'). All leaves of a JSON-path index (an index whose properties traverse a complex collection) must be contained in a single JSON column.","messagePattern":"The index (.+?) on the entity type '(.+?)' cannot be configured because its properties are mapped to different JSON columns \\('(.+?)' and '(.+?)'\\)\\. All leaves of a JSON-path index \\(an index whose properties traverse a complex collection\\) must be contained in a single JSON column\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2736,"sourceCode":"                if (index.CollectionIndices?[i] is not null)\n                {\n                    throw new InvalidOperationException(\n                        RelationalStrings.JsonPathIndexPropertyMissingJsonColumn(\n                            index.Properties.Format(),\n                            index.DeclaringEntityType.DisplayName(),\n                            property.Name));\n                }\n\n                continue;\n            }\n\n            if (firstContainer is null)\n            {\n                firstContainer = container;\n            }\n            else if (!string.Equals(firstContainer, container, StringComparison.Ordinal))\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.JsonPathIndexPropertiesInDifferentJsonColumns(\n                        index.Properties.Format(),\n                        index.DeclaringEntityType.DisplayName(),\n                        firstContainer,\n                        container));\n            }\n        }\n    }\n\n    /// <inheritdoc />\n    protected override void ValidateIndexProperty(\n        IIndex index,\n        IPropertyBase property,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        // A property declared inside a JSON-mapped complex type is a valid index target: when the\n        // path traverses a collection the index is a JSON-path index (CollectionIndices is non-null,\n        // already enforced by Index construction); otherwise it's a scalar inside a JSON document.","sourceCodeStart":2718,"sourceCodeEnd":2754,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2718-L2754","documentation":"Thrown during JSON-path index validation when two index properties in the same index are mapped to different JSON columns. EF requires all leaves of a JSON-path index (an index traversing a complex collection) to share a single JSON container column so the database can create one functional/JSON index. See RelationalModelValidator.cs:2730-2742 where firstContainer differs from the current property's container.","triggerScenarios":"Calling HasIndex with multiple properties where each traverses a different complex collection that is mapped to a different ToJson column. The validator records the first JSON container name, then throws when it encounters a second property whose GetContainerColumnName() returns a different name.","commonSituations":"An entity has two JSON columns (e.g., 'HomeAddress' and 'WorkAddress') each containing collections, and the developer tries to create a composite index spanning properties from both JSON documents.","solutions":["Split the index into separate single-column indexes, one per JSON column.","Restructure so all indexed properties live under the same JSON column.","Remove properties from the index that belong to a different JSON column."],"exampleFix":"// before: composite index spans two different JSON columns\nmodelBuilder.Entity<Person>()\n    .ComplexProperty(p => p.HomeAddresses, ab => ab.ToJson(\"home_json\"))\n    .ComplexProperty(p => p.WorkAddresses, ab => ab.ToJson(\"work_json\"));\nmodelBuilder.Entity<Person>().HasIndex(\"HomeAddresses.Zip\", \"WorkAddresses.Zip\"); // throws\n\n// after: separate indexes per JSON column\nmodelBuilder.Entity<Person>().HasIndex(\"HomeAddresses.Zip\");\nmodelBuilder.Entity<Person>().HasIndex(\"WorkAddresses.Zip\");","handlingStrategy":"validation","validationCode":"// Check that all JSON-path index properties share one JSON container.\nforeach (var index in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetDeclaredIndexes()))\n{\n    if (index.CollectionIndices is null) continue;\n    var containers = new HashSet<string>();\n    for (var i = 0; i < index.Properties.Count; i++)\n    {\n        if (index.CollectionIndices[i] is null) continue;\n        var prop = index.Properties[i];\n        var c = (prop.DeclaringType as IComplexType)?.GetContainerColumnName();\n        if (c != null) containers.Add(c);\n    }\n    if (containers.Count > 1)\n        Console.WriteLine($\"Index on {index.DeclaringEntityType.DisplayName()} spans multiple JSON columns: {string.Join(\", \", containers)}\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep composite indexes within a single JSON column; split cross-column indexes into separate index definitions.","Document which JSON column each index targets in your model configuration comments."],"tags":["index","json","complex-collection","model-validation"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}