dotnet/efcore · error · InvalidOperationException

Required JSON property '{property}' cannot contain null.

Error message

Required JSON property '{property}' cannot contain null.

What it means

Thrown by RelationalJsonUtilities.SerializeComplexTypeToJson (RelationalJsonUtilities.cs:99) while serializing an entity/complex-type value into its JSON column for SaveChanges. A scalar property declared as non-nullable (IsNullable == false) had a null CLR value at write time and the JSON value reader/writer does not handle null writes. EF refuses to write a null for a required JSON property because that would violate the model's nullability contract inside the JSON document.

Source

Thrown at src/EFCore.Relational/Query/Internal/RelationalJsonUtilities.cs:99

                return;
            }

            writer.WriteStartObject();

            foreach (var property in complexType.GetProperties())
            {
                var jsonPropertyName = property.GetJsonPropertyName();
                Check.DebugAssert(jsonPropertyName is not null);
                writer.WritePropertyName(jsonPropertyName);

                var jsonValueReaderWriter = property.GetJsonValueReaderWriter() ?? property.GetTypeMapping().JsonValueReaderWriter;

                var propertyValue = property.GetGetter().GetClrValue(objectValue);
                if (propertyValue is null && jsonValueReaderWriter?.HandlesNullWrites != true)
                {
                    if (!property.IsNullable)
                    {
                        throw new InvalidOperationException(RelationalStrings.NullValueInRequiredJsonProperty(property.Name));
                    }

                    writer.WriteNullValue();
                }
                else
                {
                    Check.DebugAssert(jsonValueReaderWriter is not null, "Missing JsonValueReaderWriter on JSON property");
                    jsonValueReaderWriter.ToJson(writer, propertyValue);
                }
            }

            foreach (var complexProperty in complexType.GetComplexProperties())
            {
                var jsonPropertyName = complexProperty.GetJsonPropertyName();
                Check.DebugAssert(jsonPropertyName is not null);
                writer.WritePropertyName(jsonPropertyName);

                var propertyValue = complexProperty.GetGetter().GetClrValue(objectValue);

View on GitHub (pinned to dbf9771522)

Solutions

  1. Ensure every non-nullable scalar property of the JSON-mapped owned/complex type has a non-null value before SaveChanges.
  2. If the property is genuinely optional, make it nullable in the model (IsRequired(false) / nullable CLR type) so EF writes a JSON null.
  3. Initialize required properties in the constructor or with default values.
  4. Validate the object graph (DataAnnotations / null checks) before calling SaveChanges to surface the bad value earlier.

Example fix

// before - required (non-nullable) 'Email' inside a JSON-mapped owned type is null
var contact = new Contact { Name = "x", Details = new ContactDetails { Phone = "555", Email = null } };
context.Add(contact);
await context.SaveChangesAsync(); // throws: Required JSON property 'Email' cannot contain null.

// after - give the required property a value, or mark it nullable in the model
var contact = new Contact { Name = "x", Details = new ContactDetails { Phone = "555", Email = "none@example.com" } };
// model: modelBuilder.Entity<Contact>().OwnsOne(c => c.Details, d => d.Property(p => p.Email).IsRequired());
// or make Email nullable if it's truly optional
Defensive patterns

Strategy: validation

Validate before calling

// Validate required (non-nullable) JSON scalar properties before SaveChanges.
static void ValidateRequiredJsonScalars(IModel model, object entity) {
    var et = model.FindEntityType(entity.GetType());
    foreach (var owned in et!.GetNavigations().Where(n => n.TargetEntityType.IsMappedToJson())) {
        var ownedValue = owned.GetGetter().GetClrValue(entity);
        if (ownedValue is null) continue;
        foreach (var p in owned.TargetEntityType.GetProperties()) {
            if (!p.IsNullable) {
                var v = p.GetGetter().GetClrValue(ownedValue);
                if (v is null) throw new ValidationException($"Required JSON property '{p.Name}' is null.");
            }
        }
    }
}

Try / catch

try { await ctx.SaveChangesAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Required JSON property")) {
    // A non-nullable JSON scalar was null at save time.
    _logger.LogError(ex, "Fix null required JSON scalar before saving.");
    throw;
}

Prevention

When it happens

Trigger: Saving an entity whose JSON-mapped owned/complex type has a non-nullable scalar property set to null. Occurs during SaveChanges/SaveChangesAsync when EF serializes the complex type to the JSON column. Common with owned types mapped ToJson or complex types where a property is required but never assigned.

Common situations: Constructing an owned/complex type without initializing all required (non-nullable) scalar properties (value types left at default, or reference types null); changing a property from nullable to required without updating data; default constructor not setting required fields; recent switch to JSON-mapped owned entities.

Related errors


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