Skip to content

validate -mt works with static graph restore #13153

@JanProvaznik

Description

@JanProvaznik

Investigation Results: -mt mode breaks NuGet static graph restore for conditional ProjectReferences

Summary

When MSBuild runs with -mt (multithreaded) mode AND RestoreUseStaticGraphEvaluation=true, conditional ProjectReference items that depend on MSBuildRestoreSessionId are not properly evaluated during graph construction, causing those projects to be excluded from restore.

Reproduction

Environment: dotnet/runtime repo with RestoreUseStaticGraphEvaluation=true (default)

Problematic pattern in src/libraries/pretest.proj:

<ExternalsProject Include="externals.csproj" ... />
<ProjectReference Include="@(ExternalsProject)" Condition="'$(MSBuildRestoreSessionId)' != ''" />

This pattern is intended to include externals.csproj as a ProjectReference only during restore (when MSBuildRestoreSessionId is set).

Test Results

Test -mt mode Static Graph Restore externals.csproj Restored NETSDK1004 Error
1 ✅ Yes ✅ Yes No Yes (BUG)
2 ✅ Yes ❌ No ✅ Yes ❌ No
3 ❌ No ✅ Yes ✅ Yes ❌ No

Commands Used

# Test 1: FAILS - externals.csproj not restored
dotnet msbuild Build.proj -restore -t:Build -p:Subset=libs.pretest -p:Configuration=Release -mt -m

# Test 2: WORKS - externals.csproj restored
dotnet msbuild Build.proj -restore -t:Build -p:Subset=libs.pretest -p:Configuration=Release -p:RestoreUseStaticGraphEvaluation=false -mt -m

# Test 3: WORKS - externals.csproj restored  
dotnet msbuild Build.proj -restore -t:Build -p:Subset=libs.pretest -p:Configuration=Release -m

Root Cause Analysis

NuGet's static graph restore uses an out-of-process tool (NuGet.Build.Tasks.Console) to evaluate projects and build the dependency graph. This tool receives global properties via IBuildEngine6.GetGlobalProperties().

When -mt mode is enabled, the MSBuildRestoreSessionId property appears to not be properly passed to the static graph evaluation, causing the condition '$(MSBuildRestoreSessionId)' != '' to evaluate as false during graph construction. This excludes the conditional ProjectReference from the restore graph.

Affected Code Paths

  • NuGet.Build.Tasks.RestoreTaskExStaticGraphRestoreTaskBase
  • NuGet.Build.Tasks.Console.MSBuildStaticGraphRestore.GetDependencyGraphSpec()
  • Global property serialization between MSBuild and the out-of-proc NuGet console

Workarounds

  1. Disable -mt for affected repos: Set <UseMSBuildMT>false</UseMSBuildMT> (current VMR approach)
  2. Disable static graph restore: Set RestoreUseStaticGraphEvaluation=false (slower)
  3. Change project pattern: Remove the MSBuildRestoreSessionId condition and always include the ProjectReference

Recommendation

This appears to be a bug in NuGet's static graph restore implementation when combined with MSBuild -mt mode. The fix likely needs to be in NuGet.Build.Tasks to ensure global properties (including MSBuildRestoreSessionId) are properly passed to the out-of-process evaluation in all modes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: Static GraphIssues with -graph, -isolate, and the related APIs.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions