{"record":{"id":"9ee1dd5e70520af1","repo":"dotnet/efcore","slug":"an-error-occurred-while-reading-a-database-value-9ee1dd","errorCode":null,"errorMessage":"An error occurred while reading a database value. The expected type was '{expectedType}' but the actual value was of type '{actualType}'.","messagePattern":"An error occurred while reading a database value\\. The expected type was '(.+?)' but the actual value was of type '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs","lineNumber":2048,"sourceCode":"            message\n                = exception is NullReferenceException\n                || Equals(value, DBNull.Value)\n                    ? RelationalStrings.ErrorMaterializingPropertyNullReference(entityType, propertyName, expectedType)\n                    : exception is InvalidCastException\n                        ? CoreStrings.ErrorMaterializingPropertyInvalidCast(entityType, propertyName, expectedType, actualType)\n                        : RelationalStrings.ErrorMaterializingProperty(entityType, propertyName);\n        }\n        else\n        {\n            message\n                = exception is NullReferenceException\n                    ? RelationalStrings.ErrorMaterializingValueNullReference(expectedType)\n                    : exception is InvalidCastException\n                        ? RelationalStrings.ErrorMaterializingValueInvalidCast(expectedType, actualType)\n                        : RelationalStrings.ErrorMaterializingValue;\n        }\n\n        throw new InvalidOperationException(message, exception);\n    }\n\n    /// <summary>\n    ///     Gets the value of JSON property name used for the given property of an entity mapped to a JSON column.\n    /// </summary>\n    /// <remarks>\n    ///     Unless configured explicitly, entity property name is used.\n    /// </remarks>\n    /// <param name=\"property\">The property.</param>\n    /// <returns>\n    ///     The value for the JSON property used to store the value of this entity property.\n    ///     By default <see langword=\"null\" /> is returned for key properties and for properties that\n    ///     are not mapped to JSON.\n    /// </returns>\n    public static string? GetJsonPropertyName(this IReadOnlyProperty property)\n        => (string?)property.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value\n            ?? (property.IsKey() || !property.DeclaringType.IsMappedToJson()\n                ? null","sourceCodeStart":2030,"sourceCodeEnd":2066,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs#L2030-L2066","documentation":"Thrown by ThrowReadValueException when the data reader returned a value whose runtime type cannot be cast to the expected CLR type, surfaced as an InvalidCastException wrapper. Fires in the property-less else branch — i.e. a projected value, not an entity property. The message reports both the expected type (the generic TValue) and the actual runtime type returned by the driver.","triggerScenarios":"Materializing a projected value where the database column type differs from the CLR type and the ADO.NET driver cannot convert (e.g. SQL column is VARCHAR but TValue is Guid; or a JSON column returns string while TValue is JObject). Distinct from the property-keyed variant because no IProperty is bound at the throw site.","commonSituations":"Raw SQL projections with FromSqlRaw into a non-entity type whose column order/types drifted from the DTO; manual DbDataReader usage bridged into EF; provider version upgrades that changed type mapping defaults (e.g. byte[] vs string); misconfigured value converters on projections.","solutions":["Align the projected CLR type with the column's mapped type — query property.GetColumnType() or sp_help to confirm.","Add a HasConversion on the source property, or coerce in the projection (e.g. b.Id.ToString()).","For FromSqlRaw, verify the SELECT column order and types match the DTO field order and types.","Upgrade the provider package in lockstep with EF Core so type mappings stay consistent."],"exampleFix":"// before\nvar ids = await db.Database.SqlQueryRaw<Guid>(\"SELECT token FROM tokens\").ToListAsync();\n\n// after — token column is varchar\nvar ids = await db.Database.SqlQueryRaw<string>(\"SELECT token FROM tokens\").ToListAsync();","handlingStrategy":"validation","validationCode":"// confirm the column type matches TValue before projecting\nvar columnType = property.GetColumnType();\nif (!typeof(TValue).IsAssignableFrom(map.GetClrType(columnType)))\n    throw new InvalidOperationException($\"Type mismatch: {columnType} -> {typeof(TValue)}\");","typeGuard":"static bool CanMapTo(Type clrType, string storeType, IRelationalTypeMappingSource src)\n    => src.FindMapping(clrType, storeType) is not null;","tryCatchPattern":"try { var v = await query.ToListAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"actual value was of type\"))\n{\n    logger.LogError(ex, \"Type mismatch during materialization; inner: {Inner}\", ex.InnerException?.Message);\n    throw;\n}","preventionTips":["Keep provider and EF Core packages version-aligned to preserve type mappings.","For FromSqlRaw, validate SELECT column order and types against the DTO.","Add HasConversion when the column type and CLR type intentionally differ."],"tags":["materialization","type-mismatch","invalid-cast","type-mapping"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}