{"record":{"id":"571f43ac7fb25223","repo":"dotnet/efcore","slug":"an-error-occurred-while-reading-a-database-value","errorCode":null,"errorMessage":"An error occurred while reading a database value. The expected type was '{expectedType}' but the actual value was 'null'.","messagePattern":"An error occurred while reading a database value\\. The expected type was '(.+?)' but the actual value was 'null'\\.","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 underlying data reader returned a null/DBNull for a value slot whose target CLR type is a non-nullable value type, and the shaper has no IProperty context (the else branch). EF wraps the NullReferenceException or DBNull-equivalent into an InvalidOperationException with a clear expected-type-vs-null message. It indicates the database row contained NULL where the materialization contract expected a value.","triggerScenarios":"A DbDataReader slot yielded DBNull (or a NullReferenceException) during materialization of a projected value with no associated IProperty — typically inside a non-entity projection (e.g. a Select(b => new Dto { Count = b.SomeInt }) where the underlying column is null). The else branch fires because property is null.","commonSituations":"Database column is nullable but the projection CLR type is non-nullable int/DateTime/Guid; a LEFT JOIN produced NULL for the right side; default constraints were dropped so newly inserted rows have NULL where EF expects a value; views with outer joins materialized into value-type DTOs.","solutions":["Make the projected CLR member nullable (int? / DateTime?) so DBNull maps cleanly.","If reading an entity, mark the property as nullable in the model (IsRequired(false)) or add a NOT NULL default constraint.","Update the database schema to disallow NULL and backfill existing NULL rows.","For DTO projections, coerce in the selector: b.SomeIntColumn ?? 0."],"exampleFix":"// before\nvar dtos = await db.Blogs\n    .Select(b => new BlogDto { Rank = b.Rank })  // Rank is int, column nullable\n    .ToListAsync();\n\n// after\npublic class BlogDto { public int? Rank { get; set; } }","handlingStrategy":"validation","validationCode":"// before materializing, ensure projected members are nullable when the column is nullable\nvar rows = await db.Blogs\n    .Select(b => new BlogDto { Rank = (int?)b.Rank })\n    .ToListAsync();","typeGuard":"// narrow value-type results defensively\nstatic T? SafeRead<T>(object? v) where T : struct => v is DBNull or null ? null : (T)v;","tryCatchPattern":"try { var v = await query.FirstAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"actual value was 'null'\"))\n{\n    logger.LogWarning(ex, \"Null in non-nullable projection; check schema/DTO\");\n    throw;\n}","preventionTips":["Make DTO members nullable when the source column permits NULL.","Add NOT NULL default constraints before relying on non-nullable reads.","For LEFT JOIN scenarios, project from the nullable side as nullable."],"tags":["materialization","null-value","value-type","data-reader"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}