Add tests for lazy-loading proxy behavior with detached entities after context disposal#37056
Closed
Copilot wants to merge 7 commits intorelease/10.0from
Closed
Add tests for lazy-loading proxy behavior with detached entities after context disposal#37056Copilot wants to merge 7 commits intorelease/10.0from
Copilot wants to merge 7 commits intorelease/10.0from
Conversation
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…gation Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Document resolution for EF Core 8 lazy-loading proxy issue
Add tests for lazy-loading proxy behavior with detached entities after context disposal
Nov 1, 2025
6 tasks
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.
User reported nondeterministic CLR hangs in EF Core 8.0.4 when accessing lazy-loaded navigation properties on detached entities after DbContext disposal. Investigation shows current implementation handles this correctly via
_detachedflag check inLazyLoader.ShouldLoad(), which returns early before accessing disposed context.Changes
Added 4 test methods covering detached entity scenarios:
Added test infrastructure:
Parent/Child/GrandChildentities andComplexGraphContextfor complex graph scenariosDocumentation: XML comments explaining each test's purpose and investigation findings
Example Scenario
All 80 tests pass. No hangs observed in any scenario, indicating current implementation is safe.
Original prompt
This section details on the original issue you should resolve
<issue_title>EF Core 8 lazy-loading proxy caused nondeterministic CLR hang, root cause and resolution</issue_title>
<issue_description>### Question
This isn’t a question, it’s a documentation post describing a resolved issue encountered during a .NET 8 EF Core migration. Posting here so others can find it if they encounter similar nondeterministic hangs or CLR stalls.
clr_corruption_case_study.md
Your code
Stack traces
Verbose output
EF Core version
8.0.4
Database provider
No response
Target framework
.NET 8.0
Operating system
macOS 26.1
IDE
Visual Studio Code 1.105.1</issue_description>
<agent_instructions>First try to create a test that accesses lazy-loaded navigations of types for which lazy-loaded proxies are created after the context was disposed. To match this issue the test should hang instead of throwing ObjectDisposedException or LazyLoadOnDisposedContextWarning. This might happen if the entry in question was detached before the context was disposed, but also explore other scenarios</agent_instructions>
Comments on the Issue (you are @copilot in this section)
@AndriySvyryd Embedding the linked file for ease of reading:When the CLR Lies: Diagnosing Nondeterministic Metadata Corruption in EF Core 8
Abstract
This case study documents a rare and deeply nondeterministic corruption event in the .NET 8 Common Language Runtime (CLR) triggered by Entity Framework Core 8 navigation proxy enumeration. During the modernization of a production-grade enterprise data-processing system, a long-running background job began freezing unpredictably inside benign control-flow branches. The failure was traced to EF Core’s internal lazy-loading proxy system, which corrupted CLR heap metadata when enumerating navigation properties on detached entities. This paper presents the investigation, root cause analysis, and resolution strategy, culminating in the development of the
SafeGetRecordspattern.1. Context and Environment
System: High-volume transactional processing service (background worker)
Legacy Stack: .NET Framework 4.8 with Entity Framework 6
Migration Target: .NET 8 with EF Core 8
Symptoms: Background job execution hung indefinitely, consuming no CPU, with no exceptions or diagnostic output.
Trigger: Occurred only when processing certain resubmitted transaction groups.
The job functioned correctly for all other inputs, suggesting a nondeterministic runtime corruption rather than a logic error.
2. Initial Observations
shouldEnterBranch == false.DbContextappeared intact prior to freeze.Debugger inspection showed a suspended thread inside the JIT evaluation pipeline — not within EF or SQL operations.
3. Discovery Path
DbContextdisposalThe corruption only occurred when an entity’s navigation collection was touched — even with benign calls like
.Count()or.ToList().4. Root Cause: EF Core Proxy Corruption
Trigger Condition: Enumerating a navigation property after the parent
DbContextwas disposed or under deferred proxy loading.Mechanism: EF Core 8 creates dynamic lazy-loading proxies through an internal
ILazyLoader. When the parent context is disposed, the proxy retains a stale pointer to theStateManager. Any subsequent enumeration attempts to resolve related entities, invoking the loader through a dangling reference.Result:
if (x)evaluations).Unlike a normal
ObjectDisposedException, this is heap-level corruption, making it appear as nondeterministic logic failure.5. Verification
Controlled tests were run:
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.