dotnet/efcore · error · InvalidOperationException
The type of the ' ' property on ' ' is ' '. All 'id'…
Error message
The type of the '{idProperty}' property on '{entityType}' is '{propertyType}'. All 'id' properties must be strings or have a string value converter. What it means
Thrown when the property mapped to the Cosmos JSON 'id' is not a string at the store level. The validator resolves the effective store type via the property's type mapping converter ProviderClrType (falling back to the ClrType) and requires it to be System.String. Cosmos stores 'id' as a string, so any non-string store type (with no converter to string) is invalid.
Solutions
- Add a string value converter to the id-mapped property: .HasConversion<string>() (or a custom converter that returns a string).
- If the property is a Guid/int/long, HasConversion<string>() is the canonical fix.
- Confirm the type mapping's ProviderClrType is string - a converter to any other type will still fail.
- Reassign the 'id' JSON mapping to a different property that is already a string.
Example fix
// before
modelBuilder.Entity<User>()
.Property(u => u.Id) // Guid
.ToJsonProperty("id");
// after
modelBuilder.Entity<User>()
.Property(u => u.Id)
.HasConversion<string>()
.ToJsonProperty("id"); Defensive patterns
Strategy: validation
Validate before calling
foreach (var et in dbContext.Model.GetEntityTypes().Where(e => e.IsDocumentRoot()))
{
var id = et.GetProperties().FirstOrDefault(p => p.GetJsonPropertyName() == CosmosJsonIdConvention.IdPropertyJsonName);
if (id is null) continue;
var storeType = id.GetTypeMapping().Converter?.ProviderClrType ?? id.ClrType;
if (storeType != typeof(string)) throw new InvalidOperationException($"{id.Name} id store type is {storeType}");
} Prevention
- Always pair a non-string PK with HasConversion<string>().
- Check the converter's ProviderClrType, not just ClrType.
- Add a model-validation test asserting the id store type is string.
When it happens
Trigger: An entity has a property mapped to the 'id' JSON name whose ClrType is int/Guid/byte[]/etc. and which has no value converter that produces a string at the provider level. Fires during ValidateKeys for document-root entity types.
Common situations: Using a Guid or int primary key directly as the id without a string conversion; mapping a byte[] token to 'id'; forgetting HasConversion<string>() after customizing the key; switching a key type and losing the converter.
Related errors
- The entity type ' ' does not have a property mapped to the…
- The type of the partition key property
- 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/da79aa0404e3a505.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:444
var primaryKey = entityType.FindPrimaryKey();
if (primaryKey == null
|| !entityType.IsDocumentRoot())
{
return;
}
var idProperty = entityType.GetProperties()
.FirstOrDefault(p => p.GetJsonPropertyName() == CosmosJsonIdConvention.IdPropertyJsonName);
if (idProperty == null)
{
throw new InvalidOperationException(CosmosStrings.NoIdProperty(entityType.DisplayName()));
}
var idType = idProperty.GetTypeMapping().Converter?.ProviderClrType
?? idProperty.ClrType;
if (idType != typeof(string))
{
throw new InvalidOperationException(
CosmosStrings.IdNonStringStoreType(idProperty.Name, entityType.DisplayName(), idType.ShortDisplayName()));
}
var partitionKeyPropertyNames = entityType.GetPartitionKeyPropertyNames();
if (partitionKeyPropertyNames.Count == 0)
{
logger.NoPartitionKeyDefined(entityType);
}
else
{
if (entityType.BaseType != null
&& entityType.FindAnnotation(CosmosAnnotationNames.PartitionKeyNames)?.Value != null)
{
throw new InvalidOperationException(
CosmosStrings.PartitionKeyNotOnRoot(entityType.DisplayName(), entityType.BaseType.DisplayName()));
}
foreach (var partitionKeyPropertyName in partitionKeyPropertyNames)View on GitHub (pinned to 3a2006ef56)