Fix NullReferenceException for mistyped default values on non-string columns in migrations#38399
Open
Copilot wants to merge 2 commits into
Open
Fix NullReferenceException for mistyped default values on non-string columns in migrations#38399Copilot wants to merge 2 commits into
Copilot wants to merge 2 commits into
Conversation
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix old migration break in EF Core 8 due to invalid default value
Fix NullReferenceException for mistyped default values on non-string columns in migrations
Jun 10, 2026
There was a problem hiding this comment.
Pull request overview
This PR fixes a regression where applying older migrations with a mistyped DefaultValue (e.g. int column with defaultValue: "") can throw a NullReferenceException in EF Core 8+ during type mapping resolution. The change prevents string from being misclassified as a primitive collection (IEnumerable<char>) in the JSON collection-mapping path, restoring the prior “fallback” behavior and producing valid SQL.
Changes:
- Update
TypeMappingSourceBase.TryFindJsonCollectionMappingto explicitly excludemodelClrType == typeof(string)from the JSON/primitive-collection mapping flow. - Add a SQL Server migrations SQL generator test covering
AddColumnOperationwith anintcolumn andstringdefault value to ensure no exception and stable SQL generation.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/EFCore/Storage/TypeMappingSourceBase.cs |
Prevents string from entering JSON collection mapping, avoiding the NRE and allowing downstream fallback mapping for mistyped defaults. |
test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs |
Adds a regression test asserting the generated SQL for the mistyped-default scenario. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migrations authored in older EF Core versions can carry a default value whose CLR type doesn't match the column's store type — e.g.
table.Column<int>(nullable: false, defaultValue: ""). This worked through EF Core 7 but throws anNullReferenceExceptionwhen applied under EF Core 8+.Root cause
MigrationsSqlGenerator.DefaultValuecallsFindMapping(typeof(string), "int"). The scalar lookup misses, so resolution falls into the collection-mapping path, whereTypeMappingSourceBase.TryFindJsonCollectionMappingtreatsstringas a primitive collection ofchar(string : IEnumerable<char>). The follow-up mapping lookup returnsnull, andnull!.WithComposedConverter(...)dereferences it.Changes
TypeMappingSourceBase.TryFindJsonCollectionMapping: guard againstmodelClrType == typeof(string).stringalways has dedicated scalar mappings and is never a JSON/primitive collection, so it should not enter this path. The mistyped default now resolves tonullandDefaultValuefalls back toGetMappingForValue, yielding valid SQL (... DEFAULT N''), matching legacy behavior.SqlServerMigrationsSqlGeneratorTest: addedAddColumnOperation_mistyped_default_legacycovering the int-column / string-default case.if ((providerClrType == null || providerClrType == typeof(string)) + && modelClrType != typeof(string) && modelClrType.TryGetElementType(typeof(IEnumerable<>)) is { } elementType && elementType != modelClrType && !modelClrType.GetGenericTypeImplementations(typeof(IDictionary<,>)).Any())