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

  1. Keep the id-mapped property as a string (let the convention map a string PK to "id").
  2. Add a value converter to string, e.g. .HasConversion(v => v.ToString(), v => Guid.Parse(v)) on the id property.
  3. 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

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


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