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

  1. Convert the value to the property's exact ClrType (or its converter's ProviderClrType) before calling Add - use Convert.ChangeType or an explicit cast.
  2. Make the producer and consumer agree on the partition key's primitive type; do not send strings where ints are expected.
  3. If you genuinely need flexibility, configure a value converter that accepts the incoming type and converts to the property type.
  4. 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

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


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)