Skip to content

Conversation

@JanProvaznik
Copy link
Member

@JanProvaznik JanProvaznik commented Jan 29, 2026

When using MSBuild's multithreaded mode (-mt / /maxcpucount), the %(RecursiveDir) built-in metadata was lost when items crossed process boundaries to the TaskHost. This caused NuGet pack to flatten directory structures (e.g., build\wix\bundle\bundle.wxs became build\bundle.wxs).

Root cause: TaskParameterTaskItem only copied custom metadata when wrapping ITaskItem for TaskHost serialization. RecursiveDir is a built-in metadata that cannot be derived from just the item spec - it requires the original wildcard pattern (_includeBeforeWildcardExpansionEscaped).

Fix: Explicitly copy RecursiveDir to custom metadata in TaskParameterTaskItem constructor before serialization, so it survives the cross-process boundary.

Also includes related fixes to ProjectItemInstance.cs:

  • Preserve _projectDirectory in copy constructor and serialization
  • Fix CreateItem(string, string, string) to use includeBeforeWildcardExpansionEscaped

related: #3121
fixes #13140

Copilot AI review requested due to automatic review settings January 29, 2026 13:35
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes loss of %(RecursiveDir) when items cross the TaskHost process boundary during multithreaded builds, preventing directory flattening in scenarios like dotnet pack.

Changes:

  • Preserve RecursiveDir by copying it into custom metadata during TaskParameterTaskItem construction for TaskHost serialization.
  • Preserve ProjectItemInstance.TaskItem’s _projectDirectory across cloning and serialization.
  • Ensure TaskItemFactory.CreateItem(string, string, string) preserves includeBeforeWildcardExpansionEscaped (needed for correct RecursiveDir semantics).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/Shared/TaskParameter.cs Copies RecursiveDir into custom metadata so it survives TaskHost serialization.
src/Build/Instance/ProjectItemInstance.cs Preserves _projectDirectory across clone/serialization; fixes task item creation to keep pre-wildcard include.

@baronfel
Copy link
Member

Oh wow - I think I got this in the RID-specific tool packaging work and worked around it without understanding what was happening. Really great identification of the problem here!

@JanProvaznik JanProvaznik force-pushed the fix-recursivedir-taskhost branch 2 times, most recently from 675e5d0 to f1be335 Compare January 29, 2026 14:00
When items were returned from MSBuild tasks (like the MSBuild task's
TargetOutputs) or passed to tasks via output parameters, the
%(RecursiveDir) built-in metadata was lost. This caused NuGet pack to
flatten directory structures (e.g., build\wix\bundle\bundle.wxs became
build\bundle.wxs), resulting in NU5118 errors.

Root causes found and fixed:

1. TaskExecutionHost.cs: When creating ProjectItemInstance from task
   outputs, only IncludeEscaped was passed to the constructor, losing
   IncludeBeforeWildcardExpansionEscaped which is required for RecursiveDir.
   Fix: Use the 5-parameter constructor that accepts both values.

2. TaskParameter.cs: TaskParameterTaskItem only copied custom metadata
   when wrapping ITaskItem for TaskHost serialization, but RecursiveDir
   is a built-in metadata computed from _includeBeforeWildcardExpansionEscaped.
   Fix: Explicitly copy RecursiveDir to custom metadata so it survives
   cross-process serialization. Added ContainsKey check before calling
   GetMetadataValueEscaped to avoid expensive FileMatcher calls.

3. ProjectItemInstance.cs: Related fixes to preserve _projectDirectory
   in copy constructor, serialization, and CreateItem methods. The
   CreateItem method now derives projectDirectory from definingProject.

Fixes dotnet#3121
@JanProvaznik JanProvaznik force-pushed the fix-recursivedir-taskhost branch from f1be335 to f17258b Compare January 29, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

-mt pack does not work on dotnet/arcade repository

2 participants