dotnet/efcore · error · InvalidOperationException
A full-text index on
Error message
A full-text index on '{entityType}' is defined over multiple properties (`{properties}`). A full-text index can only target a single property. What it means
CosmosClientWrapper throws CompositeFullTextIndex when building container indexing policy and encounters a full-text index whose index.Properties contains more than one property. Cosmos DB full-text indexes must target exactly one property; composite full-text indexes are not supported.
Solutions
- Define the full-text index over exactly one (string) property.
- Define a separate single-property full-text index for each searchable string property.
Example fix
// before
modelBuilder.Entity<Doc>()
.HasIndex(x => new { x.Title, x.Body })
.IsFullTextIndex();
// after - one full-text index per property
modelBuilder.Entity<Doc>().HasIndex(x => x.Title).IsFullTextIndex();
modelBuilder.Entity<Doc>().HasIndex(x => x.Body).IsFullTextIndex(); Defensive patterns
Strategy: validation
Validate before calling
// At model build, assert full-text indexes target exactly one property.
foreach (var idx in entityType.GetIndexes())
{
if (idx.IsFullTextIndex() == true && idx.Properties.Count > 1)
throw new InvalidOperationException($"Full-text index on {entityType.DisplayName()} targets multiple properties.");
} Type guard
static bool IsSinglePropertyFullTextIndex(IIndex idx) => idx.IsFullTextIndex() == true && idx.Properties.Count == 1;
Prevention
- Define full-text indexes over a single string property only.
- Add a model-build validator that rejects multi-property full-text indexes.
- Review all HasIndex(...).IsFullTextIndex() calls during code review.
When it happens
Trigger: Defining an index over multiple properties and marking it as a full-text index, e.g. modelBuilder.Entity<T>().HasIndex(x => new { x.A, x.B }).IsFullTextIndex().
Common situations: Reusing a composite index definition and applying full-text configuration to all its paths; bulk index configuration.
Related errors
- A vector index on ' ' is defined over properties ` `. A…
- Property ' . ' was configured for full-text search, but has…
- A full-text index is defined for
- A full-text index on
- Cosmos automatic-indexing configuration was set on entity…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/cb9996b3cabaa7d7.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs:200
{
if (index.Properties.Count > 1)
{
throw new InvalidOperationException(
CosmosStrings.CompositeVectorIndex(
index.DeclaringEntityType.DisplayName(),
string.Join(",", index.Properties.Select(e => e.Name))));
}
vectorIndexes.Add(
new VectorIndexPath { Path = GetJsonPropertyPathFromRoot(index.Properties[0]), Type = vectorIndexType.Value });
continue;
}
if (index.IsFullTextIndex() == true)
{
if (index.Properties.Count > 1)
{
throw new InvalidOperationException(
CosmosStrings.CompositeFullTextIndex(
index.DeclaringEntityType.DisplayName(),
string.Join(",", index.Properties.Select(e => e.Name))));
}
fullTextIndexPaths.Add(
new FullTextIndexPath { Path = GetJsonPropertyPathFromRoot(index.Properties[0]) });
continue;
}
var isConvention = index is IConventionIndex convIndex
&& convIndex.GetConfigurationSource() == ConfigurationSource.Convention;
if (index.Properties.Count == 1)
{
var path = GetJsonPropertyPathFromRoot(index.Properties[0]) + "/?";
if (seenIncludedPaths.Add(path))
{View on GitHub (pinned to 3a2006ef56)