dotnet/efcore · error · InvalidOperationException
The partition key value supplied for
Error message
The partition key value supplied for '{propertyType}' property '{entityType}.{property}' is of type '{valueType}'. Partition key values must be of a type assignable to the property. What it means
The nested CheckType in PartitionKeyBuilderExtensions.Add throws InvalidOperationException(CosmosStrings.PartitionKeyBadValueType) when the value's runtime type matches one of the supported primitive categories (string/bool/numeric) but does not match the expectedType derived from the property's converter or ClrType. For example, the property is declared as bool but the value supplied is a string, or the property is a string but the value is a double.
Solutions
- Convert the value to the property's exact ClrType (or its converter's ProviderClrType) before calling Add - use Convert.ChangeType or an explicit cast.
- Make the producer and consumer agree on the partition key's primitive type; do not send strings where ints are expected.
- If you genuinely need flexibility, configure a value converter that accepts the incoming type and converts to the property type.
- Validate expectedType against value.GetType() before calling Add and surface a domain-level error rather than hitting the EF exception.
Example fix
// before - throws: property is int, value came in as string from JSON
var pk = JsonSerializer.Deserialize<JsonElement>(payload).GetProperty("pk").GetString();
builder.Add(pk, intPartitionKeyProperty);
// after - convert to the property's type first
var pkString = JsonSerializer.Deserialize<JsonElement>(payload).GetProperty("pk").GetString();
builder.Add(int.Parse(pkString), intPartitionKeyProperty); Defensive patterns
Strategy: validation
Validate before calling
// Coerce the value to the property's exact type before calling Add.
static object CoerceToPropertyType(object value, IProperty property)
{
var expected = (property.GetTypeMapping().Converter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
var actual = value.GetType();
if (actual == expected) return value;
if (expected == typeof(string) && actual != typeof(string)) return Convert.ToString(value)!;
return Convert.ChangeType(value, expected);
}
builder.Add(CoerceToPropertyType(value, property), property); Type guard
static bool MatchesPropertyType(object value, IProperty property)
{
var expected = (property.GetTypeMapping().Converter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
return value.GetType() == expected;
} Prevention
- Make the producer and consumer of partition key values agree on a primitive type.
- Convert at the boundary - do not push JSON strings into int/bool partition keys.
- Unit-test partition key building with values from every input source (HTTP, JSON, DB).
- Log the expected vs actual type when validation fails for faster diagnosis.
When it happens
Trigger: Supplying a string value for a bool partition key property; supplying a double for an int partition key property when the converter expects int; supplying a numeric value where the property type is string; mixing types when building a multi-value partition key with values from loosely typed sources (e.g. deserialized JSON where everything is string).
Common situations: Reading partition key values from JSON/HTTP where they arrive as strings but the property is numeric or bool; mismatched conventions between producer and consumer of partition key values; partial migration where one side treats the key as int and the other as long.
Related errors
- The partition key value is of type
- Specified argument was out of the range of valid values…
- The partition key properties for entity type
- The partition key property
- The type of the partition key property
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/723c191c9b1b5d36.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Extensions/Internal/PartitionKeyBuilderExtensions.cs:85
case var _ when value.GetType().IsNumeric():
if (expectedType != null && !expectedType.IsNumeric())
{
CheckType(value.GetType());
}
builder.Add(Convert.ToDouble(value));
break;
default:
throw new InvalidOperationException(CosmosStrings.PartitionKeyBadValue(value.GetType()));
}
void CheckType(Type actualType)
{
if (expectedType != null && expectedType != actualType)
{
throw new InvalidOperationException(
CosmosStrings.PartitionKeyBadValueType(
expectedType.ShortDisplayName(),
property!.DeclaringType.DisplayName(),
property.Name,
actualType.DisplayName()));
}
}
}
return builder;
}
}
View on GitHub (pinned to 3a2006ef56)