-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Bug Description
When querying properties from native json columns, EF Core 10 generates
JSON_VALUE(..., '$.Property' RETURNING nvarchar(max)). This causes a fatal engine crash
on both Azure SQL and SQL Server 2025 when the query joins a wide table and selects
any column from it alongside JSON_VALUE RETURNING nvarchar(max).
Replacing RETURNING nvarchar(max) with RETURNING nvarchar(4000) fixes the crash entirely.
Since JSON_VALUE is already documented to return a maximum of nvarchar(4000) by default,
emitting RETURNING nvarchar(max) provides no practical benefit but triggers an engine bug
related to unbounded nvarchar(max) memory allocation when combined with wide table projections.
Error
Via application / remote connection:
Msg 40197, Level 20, State 12, Line 10
The service has encountered an error processing your request. Please try again. Error code 22002.
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command. The results, if any, should be discarded.
Via direct SSMS connection (TCP):
Msg 10054, Level 20, State 0, Line 0
A transport-level error has occurred when receiving results from the server.
(provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
Via direct SSMS connection (Shared Memory):
Msg 233, Level 20, State 0, Line 0
A transport-level error has occurred when receiving results from the server.
(provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)
Minimal Failing Query
SELECT
[e].[Id],
[w].[Id], -- any column from the wide joined table
JSON_VALUE([e].[Data1], '$.Name' RETURNING nvarchar(max)) AS [Name],
JSON_VALUE([e].[Data1], '$.Email' RETURNING nvarchar(max)) AS [Email]
FROM [Entities] AS [e]
INNER JOIN [WideTable] AS [w] ON [e].[WideTableId] = [w].[Id]
WHERE [e].[ForeignKeyId] = 1Where:
[e].[Data1]is a nativejsontyped column (notnvarchar(max))[WideTable]is a table with many columns (20+), regardless of which column is selected from it
Minimal Working Query
-- Option 1: replace nvarchar(max) with nvarchar(4000)
SELECT
[e].[Id],
[w].[Id],
JSON_VALUE([e].[Data1], '$.Name' RETURNING nvarchar(4000)) AS [Name],
JSON_VALUE([e].[Data1], '$.Email' RETURNING nvarchar(4000)) AS [Email]
FROM [Entities] AS [e]
INNER JOIN [WideTable] AS [w] ON [e].[WideTableId] = [w].[Id]
WHERE [e].[ForeignKeyId] = 1
-- Option 2: remove the column selected from the wide table
SELECT
[e].[Id],
JSON_VALUE([e].[Data1], '$.Name' RETURNING nvarchar(max)) AS [Name],
JSON_VALUE([e].[Data1], '$.Email' RETURNING nvarchar(max)) AS [Email]
FROM [Entities] AS [e]
INNER JOIN [WideTable] AS [w] ON [e].[WideTableId] = [w].[Id]
WHERE [e].[ForeignKeyId] = 1Exact Reproduction Conditions
Through extensive binary search testing, the crash requires all of the following:
| Condition | Required to crash |
|---|---|
JSON_VALUE RETURNING nvarchar(max) |
✅ Yes — nvarchar(4000) does not crash |
INNER JOIN on a wide table (20+ columns) |
✅ Yes — narrow tables or no JOIN do not crash |
| Any column selected from the wide joined table | ✅ Yes — JOIN without selecting from it does not crash |
Removing any one of these conditions prevents the crash.
Progression of Tests
| Test | Conditions | Result |
|---|---|---|
JSON_VALUE RETURNING nvarchar(max), no JOIN |
minimal | ✅ OK |
INNER JOIN wide table, no JSON_VALUE |
no JSON | ✅ OK |
INNER JOIN wide table + JSON_VALUE but no column selected from wide table |
partial | ✅ OK |
INNER JOIN wide table + JSON_VALUE RETURNING nvarchar(4000) + column from wide table |
bounded | ✅ OK |
INNER JOIN wide table + JSON_VALUE RETURNING nvarchar(max) + column from wide table |
full | ❌ Crash |
Schema
-- Table with native json columns
CREATE TABLE [Entities] (
[Id] int NOT NULL,
[WideTableId] int NOT NULL, -- FK to wide table
[ForeignKeyId] int NOT NULL,
[Data1] json NULL, -- native json type
[Data2] json NULL, -- native json type
)
-- Wide table (20+ columns of various types)
CREATE TABLE [WideTable] (
[Id] int NOT NULL,
-- ... 20+ columns
)Proposed Fix
EF Core should emit RETURNING nvarchar(4000) instead of RETURNING nvarchar(max)
for JSON_VALUE calls, since:
JSON_VALUEalready caps its return value atnvarchar(4000)by default —
RETURNING nvarchar(max)provides no additional data capacityRETURNING nvarchar(max)triggers an engine bug on both Azure SQL and SQL Server 2025
causing crashes when joining wide tables and selecting columns from themRETURNING nvarchar(4000)is functionally equivalent and does not trigger the crash
Workaround
Use a DbCommandInterceptor with a precise regex that targets only JSON_VALUE calls
to avoid accidentally replacing nvarchar(max) in other SQL contexts:
public class FixJsonValueInterceptor : DbCommandInterceptor
{
// Targets only RETURNING nvarchar(max) inside JSON_VALUE calls
private static readonly Regex JsonValueReturning = new(
@"JSON_VALUE\(([^)]+)\s+RETURNING\s+nvarchar\(max\)\)",
RegexOptions.Compiled
);
private static string Fix(string sql) =>
JsonValueReturning.Replace(sql, "JSON_VALUE($1 RETURNING nvarchar(4000))");
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command, CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
command.CommandText = Fix(command.CommandText);
return result;
}
public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(
DbCommand command, CommandEventData eventData,
InterceptionResult<DbDataReader> result,
CancellationToken cancellationToken = default)
{
command.CommandText = Fix(command.CommandText);
return ValueTask.FromResult(result);
}
}Register it:
options.UseSqlServer(connectionString)
.AddInterceptors(new FixJsonValueInterceptor());Environment
- EF Core version: 10.x
- Database provider: Microsoft.EntityFrameworkCore.SqlServer
- Target framework: .NET 10
- SQL Server 2025: 17.0.1105.2 (RTM-GDR, KB5077468) — ❌ crashes
- Azure SQL: 12.0.2000.8 (RTM) — ❌ crashes
- Column type: Native
json(notnvarchar(max))