dotnet/efcore · error · InvalidOperationException
The entity type '{entityType}' has property '{property}' con
Error message
The entity type '{entityType}' has property '{property}' configured as a concurrency token, but only a property mapped to '_etag' is supported as a concurrency token. Consider using 'PropertyBuilder.IsETagConcurrency'. What it means
Thrown by CosmosModelValidator.ValidateConcurrencyToken when a property is marked IsConcurrencyToken but its JSON property name is not '_etag'. Cosmos DB only supports optimistic concurrency via the system _etag field, so any other concurrency token is meaningless and rejected. The message recommends PropertyBuilder.IsETagConcurrency as the correct API.
Source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:741
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual void ValidateConcurrencyToken(
IProperty property,
ITypeBase structuralType,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
if (property.IsConcurrencyToken)
{
var storeName = property.GetJsonPropertyName();
if (storeName != "_etag")
{
throw new InvalidOperationException(CosmosStrings.NonETagConcurrencyToken(structuralType.DisplayName(), storeName));
}
var etagType = property.GetTypeMapping().Converter?.ProviderClrType ?? property.ClrType;
if (etagType != typeof(string))
{
throw new InvalidOperationException(
CosmosStrings.ETagNonStringStoreType(property.Name, structuralType.DisplayName(), etagType.ShortDisplayName()));
}
}
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override void ValidateTrigger(View on GitHub (pinned to dbf9771522)
Solutions
- Replace IsConcurrencyToken/IsRowVersion with the Cosmos-specific IsETagConcurrency extension on the property builder.
- If you keep a separate property, ensure its JSON property name maps to '_etag' via HasJsonPropertyName("_etag") and that it is the etag concurrency property.
Example fix
// before
modelBuilder.Entity<Item>()
.Property(i => i.Version)
.IsRowVersion();
// after
modelBuilder.Entity<Item>()
.Property(i => i.ETag)
.HasJsonPropertyName("_etag")
.IsETagConcurrency(); Defensive patterns
Strategy: validation
Validate before calling
// Fail fast if a concurrency token is not the etag
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
foreach (var prop in et.GetProperties())
{
if (prop.IsConcurrencyToken && prop.GetJsonPropertyName() != "_etag")
{
throw new InvalidOperationException($"{et.DisplayName()}.{prop.Name} is a concurrency token but not _etag.");
}
}
} Prevention
- On Cosmos entities, always use the IsETagConcurrency extension instead of IsConcurrencyToken/IsRowVersion.
- Keep a single string ETag property per Cosmos entity mapped to '_etag'.
When it happens
Trigger: Calling builder.Property(x => x.Version).IsRowVersion() or IsConcurrencyToken() on a Cosmos entity without mapping that property to the _etag JSON name.
Common situations: Porting a relational model that uses a RowVersion/Timestamp column for optimistic concurrency. Using a shared entity type across SQL Server and Cosmos where the relational concurrency column is not an etag on Cosmos.
Related errors
- The type of the etag property '{property}' on '{entityType}'
- A full-text index on '{entityType}' is defined over multiple
- A full-text index is defined for `{entityType}.{property}`,
- The property '{propertyType} {structuralType}.{property}' ha
- Trigger '{trigger}' is defined on entity type '{entityType}'
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/e1d8776af1480bea.
Report an issue: GitHub.