dotnet/efcore · error · InvalidOperationException
The type of the '{idProperty}' property on '{entityType}' is
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 by ValidateKeys when the property mapped to JSON "id" has a store type (ClrType after applying any value converter) that is not System.String. Cosmos requires the document "id" to be a string, so the id-mapped property must either be a string or have a value converter whose ProviderClrType is string.
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 dbf9771522)
Solutions
- Keep the id-mapped property as a string (let the convention map a string PK to "id").
- Add a value converter to string, e.g. .HasConversion(v => v.ToString(), v => Guid.Parse(v)) on the id property.
- Do not remap a non-string PK onto "id"; let the convention synthesize the string id.
Example fix
// before
modelBuilder.Entity<Thing>()
.Property(t => t.Id) // Guid
.ToJsonProperty("id");
// after
modelBuilder.Entity<Thing>()
.Property(t => t.Id)
.ToJsonProperty("id")
.HasConversion(v => v.ToString(), v => Guid.Parse(v)); Defensive patterns
Strategy: validation
Validate before calling
using var ctx = new MyContext();
foreach (var e in ctx.Model.GetEntityTypes().Where(t => t.FindPrimaryKey() != null && t.IsDocumentRoot()))
{
var idProp = e.GetProperties().FirstOrDefault(p => p.GetJsonPropertyName() == "id");
if (idProp is not null)
{
var storeType = idProp.GetTypeMapping().Converter?.ProviderClrType ?? idProp.ClrType;
Debug.Assert(storeType == typeof(string), $"{e.Name}.{idProp.Name} id store type {storeType} is not string");
}
} Try / catch
try { ctx.Model.GetModel(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("All 'id' properties must be strings"))
{
logger.LogError(ex, "The id-mapped property is not a string and has no string converter");
throw;
} Prevention
- Use a string primary key for the id-mapped property, or add a string value converter.
- Do not remap non-string PKs onto JSON 'id'.
- Add a test asserting the id store type is string.
When it happens
Trigger: Mapping a Guid/int/long primary key to JSON "id" (ToJsonProperty("id")) without a string value converter, defeating the convention's default behavior.
Common situations: Forcing a non-string PK onto "id"; adding ToJsonProperty("id") to a numeric property; a value converter that converts to a non-string provider type.
Related errors
- The entity type '{entityType}' does not have a property mapp
- The type of the partition key property '{property}' on '{ent
- The time to live for analytical store was configured to '{tt
- The default time to live was configured to '{ttl1}' on '{ent
- The provisioned throughput was configured to '{throughput1}'
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/da79aa0404e3a505.
Report an issue: GitHub.