dotnet/efcore · error · InvalidOperationException
The index on the entity type ' ' cannot be configured…
Error message
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. What it means
A single JSON-path index must keep ALL leaf properties inside ONE JSON column. The validator records the first property's container column name and throws as soon as a later property's container column differs. Splitting a composite index across two JSON documents cannot be expressed as one index.
Solutions
- Keep every property of the index within the same JSON container column.
- Split the composite index into one index per JSON column so each index targets a single document.
- If the properties really belong together, merge them into one JSON-mapped complex type.
Example fix
// before — leaves in two different JSON columns -> [445]
modelBuilder.Entity<Record>()
.OwnsOne(r => r.Meta, m => m.ToJson("meta"))
.OwnsOne(r => r.Body, b => b.ToJson("body"))
.HasIndex(r => new { r.Meta!.Tag, r.Body!.Kind });
// after — one index per JSON column
modelBuilder.Entity<Record>()
.OwnsOne(r => r.Meta, m => m.ToJson("meta"))
.OwnsOne(r => r.Body, b => b.ToJson("body"));
modelBuilder.Entity<Record>().OwnsOne(r => r.Meta).HasIndex(m => m.Tag);
modelBuilder.Entity<Record>().OwnsOne(r => r.Body).HasIndex(b => b.Kind); Defensive patterns
Strategy: validation
Validate before calling
// All leaves of a JSON-path index must share one container column.
static bool IndexUsesSingleJsonContainer(IIndex index)
{
string? first = null;
foreach (var p in index.Properties)
{
string? container = p.DeclaringType is IReadOnlyComplexType ct && ct.IsMappedToJson() ? ct.GetContainerColumnName()
: p is IReadOnlyComplexProperty cp && cp.ComplexType.IsMappedToJson() ? cp.ComplexType.GetContainerColumnName()
: null;
if (container is null) continue;
if (first is null) first = container;
else if (first != container) return false;
}
return true;
} Prevention
- Keep composite JSON indexes within a single JSON column.
- Split cross-column composite indexes into one index per JSON document.
- Document which JSON column each index targets to prevent regressions.
When it happens
Trigger: Building a composite .HasIndex((e) => new { e.Doc1.Foo, e.Doc2.Bar }) where Doc1 and Doc2 are two different JSON-mapped complex properties with different container column names.
Common situations: Indexing across two JSON columns; refactoring that split one JSON document into two; copy-paste of index definitions across entities with different JSON containers.
Related errors
- The index on the entity type ' ' cannot be configured…
- The index on the entity type ' ' cannot contain the complex…
- A full-text index is defined for
- A full-text index on
- A partition key is defined on entity type
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/567b2283ec143045.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2736
if (index.CollectionIndices?[i] is not null)
{
throw new InvalidOperationException(
RelationalStrings.JsonPathIndexPropertyMissingJsonColumn(
index.Properties.Format(),
index.DeclaringEntityType.DisplayName(),
property.Name));
}
continue;
}
if (firstContainer is null)
{
firstContainer = container;
}
else if (!string.Equals(firstContainer, container, StringComparison.Ordinal))
{
throw new InvalidOperationException(
RelationalStrings.JsonPathIndexPropertiesInDifferentJsonColumns(
index.Properties.Format(),
index.DeclaringEntityType.DisplayName(),
firstContainer,
container));
}
}
}
/// <inheritdoc />
protected override void ValidateIndexProperty(
IIndex index,
IPropertyBase property,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
// A property declared inside a JSON-mapped complex type is a valid index target: when the
// path traverses a collection the index is a JSON-path index (CollectionIndices is non-null,
// already enforced by Index construction); otherwise it's a scalar inside a JSON document.View on GitHub (pinned to 3a2006ef56)