{"record":{"id":"1af626c52fa808c9","repo":"dotnet/efcore","slug":"invalid-token-type-tokentype-1af626","errorCode":null,"errorMessage":"Invalid token type: '{tokenType}'.","messagePattern":"Invalid token type: '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Storage/Internal/CosmosJsonNumberProjectionReaderWriter.cs","lineNumber":35,"sourceCode":"///     Projections of numbers in cosmos can result in double precision floating point numbers,\n///     and thus have to be read as doubles to prevent reader exceptions\n/// </remarks>\npublic sealed class CosmosJsonNumberProjectionReaderWriter<T> : JsonValueReaderWriter<T>\n    where T : INumber<T>\n{\n    private static readonly PropertyInfo\n        InstanceProperty = typeof(CosmosJsonNumberProjectionReaderWriter<T>).GetProperty(nameof(Instance))!;\n\n    /// <summary>\n    ///     The singleton instance of this stateless reader/writer.\n    /// </summary>\n    public static CosmosJsonNumberProjectionReaderWriter<T> Instance { get; } = new();\n\n    /// <inheritdoc />\n    public override T FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)\n        => manager.CurrentReader.TryGetDouble(out var d)\n            ? T.CreateChecked(d) // #38138\n            : throw new InvalidOperationException(CoreStrings.JsonReaderInvalidTokenType(manager.CurrentReader.TokenType));\n\n    /// <inheritdoc />\n    public override void ToJsonTyped(Utf8JsonWriter writer, T value)\n    {\n        if (typeof(T) == typeof(int)\n            || typeof(T) == typeof(short)\n            || typeof(T) == typeof(sbyte)\n            || typeof(T) == typeof(byte)\n            || typeof(T) == typeof(ushort))\n        {\n            writer.WriteNumberValue(int.CreateChecked(value));\n        }\n        else if (typeof(T) == typeof(uint))\n        {\n            writer.WriteNumberValue(uint.CreateChecked(value));\n        }\n        else if (typeof(T) == typeof(long))\n        {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Cosmos/Storage/Internal/CosmosJsonNumberProjectionReaderWriter.cs#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","If you intentionally store numbers as strings, configure an appropriate value converter AND a matching JsonValueReaderWriter so EF reads the correct token type.","Check for null values in non-nullable numeric columns and either make the property nullable or fix the data.","Inspect the stored document JSON (e.g., via Cosmos Data Explorer) to identify the token-type mismatch."],"exampleFix":"// before — data stored as \"count\": \"42\" (string)\n// EF reads int, TryGetDouble fails on string token\n\n// after — fix the stored data to numeric\n// \"count\": 42\n// or configure a reader/writer if string storage is intentional:\nmodelBuilder.Entity<Item>()\n    .Property(i => i.Count)\n    .HasConversion(\n        v => v.ToString(),\n        v => int.Parse(v));\n// and ensure the JsonValueReaderWriter handles string tokens","handlingStrategy":"try-catch","validationCode":"// Before querying, verify stored data types match the model by sampling a document via the Cosmos SDK.\nvar container = cosmosClient.GetContainer(db, containerName);\nvar sample = await container.ReadItemAsync<JObject>(someId, new PartitionKey(pk));\nvar token = sample.Resource[\"count\"]?.Type;\nif (token != JTokenType.Integer && token != JTokenType.Float)\n    throw new InvalidOperationException($\"Stored 'count' is {token}, expected numeric.\");","typeGuard":null,"tryCatchPattern":"// Catch during query and log the property/token for diagnosis.\ntry { var results = await db.Items.Where(i => i.Count > 0).ToListAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Invalid token type\"))\n{ /* inspect stored JSON, fix data or converter, then retry */ }","preventionTips":["Ensure numeric properties are stored as JSON numbers, not strings.","If using value converters that change the wire type, configure a matching JsonValueReaderWriter.","Validate sample documents via Cosmos Data Explorer before relying on EF queries.","Add data-integration tests that round-trip numeric properties through save and query."],"tags":["cosmos","json-serialization","type-mismatch","data-integrity"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}