dotnet/efcore · error · InvalidOperationException

The index over properties '{properties}' is declared on owne

Error message

The index over properties '{properties}' is declared on owned type '{ownedEntityType}', which is mapped to container '{containerEntityType}'. Indexes that traverse owned types are not currently supported.

What it means

Thrown by ValidateContainerIndexing while walking the owned-type tree (EnumerateContainerIndexes) when a regular (non-vector, non-full-text) index is declared on an owned entity type. The validator walks ownership navigations from each document root; any HasIndex declared on a non-document-root type that is not a vector or full-text index is rejected, because Cosmos indexes cannot traverse embedded owned documents in the relational sense.

Source

Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:389

                        throw new InvalidOperationException(
                            CosmosStrings.InconsistentAutomaticIndexing(
                                container,
                                automaticIndexingOwner.DisplayName(),
                                entityType.DisplayName()));
                    }
                }
            }

            // Walk the full owned/complex tree to surface every HasIndex declared in this container.
            // Vector and full-text indexes are allowed to traverse owned types; only regular indexes are
            // rejected
            foreach (var (declaringEntityType, index) in EnumerateContainerIndexes(entityType))
            {
                if (!declaringEntityType.IsDocumentRoot()
                    && index.GetVectorIndexType() == null
                    && index.IsFullTextIndex() != true)
                {
                    throw new InvalidOperationException(
                        CosmosStrings.IndexOnOwnedType(
                            string.Join(",", index.Properties.Select(e => e.Name)),
                            declaringEntityType.DisplayName(),
                            entityType.DisplayName()));
                }
            }
        }
    }

    private static IEnumerable<(IEntityType DeclaringEntityType, IIndex Index)> EnumerateContainerIndexes(IEntityType root)
    {
        foreach (var index in root.GetIndexes())
        {
            yield return (root, index);
        }

        foreach (var ownedNav in root.GetNavigations()
                     .Where(n => n.ForeignKey.IsOwnership && !n.IsOnDependent && !n.TargetEntityType.IsDocumentRoot()))

View on GitHub (pinned to dbf9771522)

Solutions

  1. Remove the HasIndex from the owned type.
  2. If you need to query by the nested value, declare the index on the document-root entity over the flattened path, or restructure the property onto the root.
  3. If the index is genuinely a vector or full-text index, use the vector/full-text APIs which are allowed to traverse owned types.

Example fix

// before
modelBuilder.Entity<Customer>().OwnsOne(c => c.Address, a =>
{
    a.HasIndex(x => x.PostalCode); // Address is owned -> rejected
});

// after
modelBuilder.Entity<Customer>().OwnsOne(c => c.Address);
// query by the nested JSON path directly; no HasIndex on the owned type
Defensive patterns

Strategy: validation

Validate before calling

using var ctx = new MyContext();
foreach (var root in ctx.Model.GetEntityTypes().Where(e => e.FindPrimaryKey() != null))
{
    foreach (var nav in root.GetNavigations().Where(n => n.ForeignKey.IsOwnership && !n.IsOnDependent))
    {
        foreach (var idx in nav.TargetEntityType.GetIndexes())
        {
            var isVector = idx.GetVectorIndexType() is not null;
            var isFullText = idx.IsFullTextIndex() == true;
            Debug.Assert(isVector || isFullText,
                $"Index [{string.Join(",", idx.Properties.Select(p => p.Name))}] on owned {nav.TargetEntityType.Name} is not allowed (only vector/full-text may traverse owned types).");
        }
    }
}

Try / catch

try { ctx.Model.GetModel(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Indexes that traverse owned types are not currently supported"))
{
    logger.LogError(ex, "A regular HasIndex was declared on an owned type");
    throw;
}

Prevention

When it happens

Trigger: Calling modelBuilder.Entity<Owner>().OwnsOne(o => o.Address, a => a.HasIndex(x => x.Zip)) where Address is an owned type embedded in the Owner document. Regular indexes on owned types are unsupported; only vector and full-text indexes may cross the ownership boundary.

Common situations: Porting a relational model that indexed properties now nested inside owned types; wanting to 'speed up' lookups on a nested value; treating owned types like separate tables.

Related errors


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