{"record":{"id":"964072a6fbd604e1","repo":"dotnet/efcore","slug":"complex-property-complexproperty-cannot-have-b","errorCode":null,"errorMessage":"Complex property '{complexProperty}' cannot have both a JSON column name ('{columnName}') and a JSON property name ('{propertyName}') configured. Use 'ToJson()' to map to a JSON column or 'HasJsonPropertyName()' to map as a JSON property within a containing JSON column, but not both.","messagePattern":"Complex property '(.+?)' cannot have both a JSON column name \\('(.+?)'\\) and a JSON property name \\('(.+?)'\\) configured\\. Use 'ToJson\\(\\)' to map to a JSON column or 'HasJsonPropertyName\\(\\)' to map as a JSON property within a containing JSON column, but not both\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":286,"sourceCode":"        {\n            throw new InvalidOperationException(\n                RelationalStrings.ComplexCollectionNotMappedToJson(\n                    complexProperty.DeclaringType.DisplayName(), complexProperty.Name));\n        }\n\n        if (!complexProperty.ComplexType.IsMappedToJson()\n            && complexProperty.IsNullable\n            && complexProperty.ComplexType.GetProperties().All(m => m.IsNullable))\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.ComplexPropertyOptionalTableSharing(complexProperty.ComplexType.DisplayName(), complexProperty.Name));\n        }\n\n        if (complexProperty.GetJsonPropertyName() != null)\n        {\n            if (complexProperty.ComplexType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName)?.Value is string columnName)\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.ComplexPropertyBothJsonColumnAndJsonPropertyName(\n                        $\"{complexProperty.DeclaringType.DisplayName()}.{complexProperty.Name}\",\n                        columnName,\n                        complexProperty.GetJsonPropertyName()));\n            }\n\n            if (!complexProperty.DeclaringType.IsMappedToJson())\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.ComplexPropertyJsonPropertyNameWithoutJsonMapping(\n                        $\"{complexProperty.DeclaringType.DisplayName()}.{complexProperty.Name}\"));\n            }\n        }\n\n        if (complexProperty.ComplexType.IsMappedToJson())\n        {\n            if (!complexProperty.DeclaringType.IsMappedToJson()\n                && complexProperty.DeclaringType is IComplexType)","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L268-L304","documentation":"ValidatePropertyMapping (RelationalModelExtensions.cs:282-291) throws when a complex property simultaneously has a JSON column name annotation (ContainerColumnName, set via ToJson/HasContainerColumnName) AND a JSON property name annotation (JsonPropertyName, set via HasJsonPropertyName). These describe mutually exclusive mappings: ToJson maps the property to its own JSON column, HasJsonPropertyName maps it as a key inside an enclosing JSON column. Specifying both is contradictory.","triggerScenarios":"Calling both ToJson(\"col\") (or HasContainerColumnName) and HasJsonPropertyName(\"key\") on the same complex property. Thrown at model validation.","commonSituations":"Copy-pasting JSON config; refactoring a complex type from a standalone JSON column into a nested property but leaving the old ToJson() call in place.","solutions":["If the complex property should be its own JSON column, keep ToJson() and remove HasJsonPropertyName().","If the complex property should be a JSON key inside an owning JSON column, keep HasJsonPropertyName() and remove ToJson()/HasContainerColumnName(), ensuring the containing type is JSON-mapped.","Audit the configuration chain so only one JSON mapping intent is expressed."],"exampleFix":"// before - both mappings\nmodelBuilder.Entity<Order>().OwnsOne(o => o.Billing, b =>\n{\n    b.ToJson(\"BillingJson\");\n    b.HasJsonPropertyName(\"bill\"); // throws: cannot have both\n});\n\n// after - pick one (own JSON column)\nmodelBuilder.Entity<Order>().OwnsOne(o => o.Billing, b =>\n{\n    b.ToJson(\"BillingJson\");\n});\n// OR (nested inside another JSON column)\n// b.HasJsonPropertyName(\"bill\");","handlingStrategy":"validation","validationCode":"foreach (var et in context.Model.GetEntityTypes())\n{\n    foreach (var cp in et.GetComplexProperties())\n    {\n        bool hasColumnName = cp.ComplexType\n            .FindAnnotation(RelationalAnnotationNames.ContainerColumnName)?.Value is string;\n        bool hasJsonProperty = cp.GetJsonPropertyName() != null;\n        if (hasColumnName && hasJsonProperty)\n        {\n            // will throw - keep only one JSON mapping intent.\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call both ToJson()/HasContainerColumnName and HasJsonPropertyName on the same property.","Decide JSON-column vs JSON-key mapping per complex property and apply only that API.","Audit JSON config after refactoring complex types."],"tags":["json-mapping","complex-type","conflicting-config","model-validation"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}