dotnet/efcore · error · InvalidOperationException

Invalid token type: '{tokenType}'.

Error message

Invalid token type: '{tokenType}'.

What it means

CosmosJsonNumberProjectionReaderWriter<T>.FromJsonTyped (CosmosJsonNumberProjectionReaderWriter.cs:32-35) reads a projected numeric column. Cosmos projects all numbers as double-precision floating point, so the reader calls TryGetDouble. If the JSON token is not a number (e.g., String, Null, True, StartObject), TryGetDouble returns false and the code throws indicating the unexpected token type. This is typically a data/schema mismatch where a value that EF expects to be numeric is stored as a different JSON type.

Source

Thrown at src/EFCore.Cosmos/Storage/Internal/CosmosJsonNumberProjectionReaderWriter.cs:35

///     Projections of numbers in cosmos can result in double precision floating point numbers,
///     and thus have to be read as doubles to prevent reader exceptions
/// </remarks>
public sealed class CosmosJsonNumberProjectionReaderWriter<T> : JsonValueReaderWriter<T>
    where T : INumber<T>
{
    private static readonly PropertyInfo
        InstanceProperty = typeof(CosmosJsonNumberProjectionReaderWriter<T>).GetProperty(nameof(Instance))!;

    /// <summary>
    ///     The singleton instance of this stateless reader/writer.
    /// </summary>
    public static CosmosJsonNumberProjectionReaderWriter<T> Instance { get; } = new();

    /// <inheritdoc />
    public override T FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
        => manager.CurrentReader.TryGetDouble(out var d)
            ? T.CreateChecked(d) // #38138
            : throw new InvalidOperationException(CoreStrings.JsonReaderInvalidTokenType(manager.CurrentReader.TokenType));

    /// <inheritdoc />
    public override void ToJsonTyped(Utf8JsonWriter writer, T value)
    {
        if (typeof(T) == typeof(int)
            || typeof(T) == typeof(short)
            || typeof(T) == typeof(sbyte)
            || typeof(T) == typeof(byte)
            || typeof(T) == typeof(ushort))
        {
            writer.WriteNumberValue(int.CreateChecked(value));
        }
        else if (typeof(T) == typeof(uint))
        {
            writer.WriteNumberValue(uint.CreateChecked(value));
        }
        else if (typeof(T) == typeof(long))
        {

View on GitHub (pinned to dbf9771522)

Solutions

  1. Ensure numeric properties are stored as JSON numbers in the container, not strings or other types. If data was written incorrectly, migrate it to numeric form.
  2. If you intentionally store numbers as strings, configure an appropriate value converter AND a matching JsonValueReaderWriter so EF reads the correct token type.
  3. Check for null values in non-nullable numeric columns and either make the property nullable or fix the data.
  4. Inspect the stored document JSON (e.g., via Cosmos Data Explorer) to identify the token-type mismatch.

Example fix

// before — data stored as "count": "42" (string)
// EF reads int, TryGetDouble fails on string token

// after — fix the stored data to numeric
// "count": 42
// or configure a reader/writer if string storage is intentional:
modelBuilder.Entity<Item>()
    .Property(i => i.Count)
    .HasConversion(
        v => v.ToString(),
        v => int.Parse(v));
// and ensure the JsonValueReaderWriter handles string tokens
Defensive patterns

Strategy: try-catch

Validate before calling

// Before querying, verify stored data types match the model by sampling a document via the Cosmos SDK.
var container = cosmosClient.GetContainer(db, containerName);
var sample = await container.ReadItemAsync<JObject>(someId, new PartitionKey(pk));
var token = sample.Resource["count"]?.Type;
if (token != JTokenType.Integer && token != JTokenType.Float)
    throw new InvalidOperationException($"Stored 'count' is {token}, expected numeric.");

Try / catch

// Catch during query and log the property/token for diagnosis.
try { var results = await db.Items.Where(i => i.Count > 0).ToListAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Invalid token type"))
{ /* inspect stored JSON, fix data or converter, then retry */ }

Prevention

When it happens

Trigger: Querying a property that EF maps as a numeric type (int, long, decimal, etc.) but whose stored JSON value is a string, null, boolean, or object. This happens when data was written outside EF (e.g., via raw SDK or migration tool) with a different type, or when a value converter changes the on-wire representation in a way that conflicts with the projection reader.

Common situations: Storing numbers as JSON strings in the container (e.g., "42" instead of 42) via a different writer. Using a value converter that serializes numbers as strings but EF's projection reader expects a numeric token. Schema drift after changing a property type. Reading data inserted by a legacy app that stringified numbers.

Understand the failure class

Related errors


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