Skip to content

Fix IBuildEngine9.RequestCores returning 0 causing ReleaseCores(0) to throw in WASM/Mono build tasks#125714

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/disable-parallel-emcc-compile
Closed

Fix IBuildEngine9.RequestCores returning 0 causing ReleaseCores(0) to throw in WASM/Mono build tasks#125714
Copilot wants to merge 2 commits intomainfrom
copilot/disable-parallel-emcc-compile

Conversation

Copy link
Contributor

Copilot AI commented Mar 18, 2026

IBuildEngine9.RequestCores(n) can return 0 in resource-constrained CI Docker environments. Calling ReleaseCores(0) then throws ArgumentOutOfRangeException. Additionally, when the task runs in an out-of-process MSBuild task host, IBuildEngine callbacks fail with MSB5022 — an exception type not covered by the existing catch (NotImplementedException).

Description

Four MSBuild tasks shared the same broken IBuildEngine9 usage pattern:

  • EmccCompile (WasmAppBuilder)
  • MonoAOTCompiler
  • ILStrip
  • EmitBundleBase

Changes applied consistently to all four:

  • Guard ReleaseCores(0): Store the return value of RequestCores in a local; only update allowedParallelism and keep be9 non-null when the grant is > 0. When 0 is returned, set be9 = null so the finally-block be9?.ReleaseCores(...) is skipped.

  • Broaden exception catch: catch (NotImplementedException)catch (Exception) to also handle the MSB5022 error thrown by the out-of-process task host when IBuildEngine callbacks are unsupported.

// Before
if (be9 is not null)
    allowedParallelism = be9.RequestCores(allowedParallelism);
// ...
catch (NotImplementedException) { be9 = null; }
// finally: be9?.ReleaseCores(allowedParallelism);  ← throws if 0 was granted

// After
if (be9 is not null)
{
    int requestedCores = be9.RequestCores(allowedParallelism);
    if (requestedCores > 0)
        allowedParallelism = requestedCores;
    else
        be9 = null;  // skip ReleaseCores — nothing was granted
}
// ...
catch (Exception) { be9 = null; }  // covers MSB5022 and NotImplementedException

Customer Impact

WASM/Mono AOT publish fails with an unhandled ArgumentOutOfRangeException or MSB5022 when using /p:DisableParallelEmccCompile=true /p:DisableParallelAot=true in resource-constrained Docker CI environments. Build is completely broken in that configuration.

Regression

Yes — the root regression was introduced in .NET 9 by PR #104141 (commit f8bcb89, Jul 2024), which added ReleaseCores calls to all four tasks without guarding against RequestCores returning 0. A partial mitigation was added in .NET 10 by PR #111751 (commit 2eb6459, Jan 2025), which introduced catch (NotImplementedException) to handle task host failures and extended the pattern to EmitBundleBase, but the 0-return-value case remained unfixed. The issue was first reported against .NET 11 preview 3, where it surfaced in resource-constrained Docker CI environments.

Testing

Verified all three affected projects (WasmAppBuilder, MonoAOTCompiler, MonoTargetsTasks) build cleanly with 0 errors/warnings. The failure is environment-specific (Docker + resource constraints + task host), so automated reproduction requires that setup.

Risk

Low. The fix is a narrow, consistent change to parallelism bookkeeping that is purely defensive — on the normal code path (task host supports IBuildEngine9 and grants cores), behavior is identical to before.

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

Original prompt

This section details on the original issue you should resolve

<issue_title>[browser][docker] DisableParallelEmccCompile - MSB5022: The MSBuild task host does not support running tasks that perform IBuildEngine callbacks</issue_title>
<issue_description>### Description

The EmccCompile task in .NET 11 preview SDK calls IBuildEngine9.RequestCores(1) which returns 0 in the resource-constrained CI Docker container. The task then calls ReleaseCores(0) which throws ArgumentOutOfRangeException(coresToRelease). Despite MSBuildDisableTaskHost=true being set, the task still runs in the out-of-process task host where IBuildEngine callbacks fail with MSB5022.

Reproduction Steps

/p:MSBuildDisableTaskHost=true /p:DisableParallelEmccCompile=true /p:DisableParallelAot=true

Expected behavior

no error

Actual behavior

dotnet publish: /bench/artifacts/sdks/linux.sdk11.0.100-preview.3.26160.114/dotnet publish /__w/macro-benchmarks/macro-benchmarks/src/micro-benchmarks --no-restore /p:BenchmarkPreset=Aot -c Release /p:RuntimeFlavor=Mono /p:BuildLabel=11.0.100-preview.3.26160.114 /p:MSBuildDisableTaskHost=true /p:DisableParallelEmccCompile=true /p:DisableParallelAot=true -bl:/bench/artifacts/publish/micro-benchmarks/11.0.100-preview.3.26160.114/aot/publish.binlog -o /bench/artifacts/publish/micro-benchmarks/11.0.100-preview.3.26160.114/aot
/bench/artifacts/sdks/linux.sdk11.0.100-preview.3.26160.114/sdk/11.0.100-preview.3.26160.114/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.RuntimeIdentifierInference.targets(383,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [/__w/macro-benchmarks/macro-benchmarks/src/micro-benchmarks/MicroBenchmarks.csproj]
  MicroBenchmarks -> /__w/macro-benchmarks/macro-benchmarks/artifacts/bin/MicroBenchmarks/11.0.100-preview.3.26160.114/Aot/bin/MicroBenchmarks/release/MicroBenchmarks.dll
  Using BenchmarkPreset: 'Aot'
  Optimizing assemblies for size. This process might take a while.
  AOT'ing 10 assemblies
  [1/10] MicroBenchmarks.dll -> MicroBenchmarks.dll.bc
  [2/10] System.Collections.dll -> System.Collections.dll.bc
  [3/10] System.Console.dll -> System.Console.dll.bc
  [4/10] System.IO.Pipelines.dll -> System.IO.Pipelines.dll.bc
  [5/10] System.Memory.dll -> System.Memory.dll.bc
  [6/10] System.Runtime.InteropServices.JavaScript.dll -> System.Runtime.InteropServices.JavaScript.dll.bc
  [7/10] System.Security.Cryptography.dll -> System.Security.Cryptography.dll.bc
  [8/10] System.Text.Json.dll -> System.Text.Json.dll.bc
  [9/10] System.Private.CoreLib.dll -> System.Private.CoreLib.dll.bc
  [10/10] aot-instances.dll -> aot-instances.dll.bc
  IL stripping assemblies
  Compiling assembly bitcode files with -O2 ...
/bench/artifacts/sdks/linux.sdk11.0.100-preview.3.26160.114/packs/Microsoft.NET.Runtime.WebAssembly.Sdk/11.0.0-preview.3.26160.114/Sdk/WasmApp.Common.targets(831,5): 
error : MSB5022: The MSBuild task host does not support running tasks that perform IBuildEngine callbacks. If you wish to perform these operations, please run your task in the core MSBuild process instead.  A task will automatically execute in the task host if the UsingTask has been attributed with a "Runtime" or "Architecture" value, or the task invocation has been attributed with an "MSBuildRuntime" or "MSBuildArchitecture" value, that does not match the current runtime or architecture of MSBuild. [/__w/macro-benchmarks/macro-benchmarks/src/micro-benchmarks/MicroBenchmarks.csproj]
/bench/artifacts/sdks/linux.sdk11.0.100-preview.3.26160.114/packs/Microsoft.NET.Runtime.WebAssembly.Sdk/11.0.0-preview.3.26160.114/Sdk/WasmApp.Common.targets(831,5): 
error MSB4018: The "EmccCompile" task failed unexpectedly. [/__w/macro-benchmarks/macro-benchmarks/src/micro-benchmarks/MicroBenchmarks.csproj]

Regression?

Net11

Known Workarounds

-m:1 to paramater to msbuild cli

Configuration

github actions docker

Other information

No response</issue_description>

<agent_instructions>- check if (be9 is not null) and wrap it in try/catch.

  • find all locations in the codebase which use IBuildEngine9</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 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.

… throw, and catch broader exceptions for task host compatibility

Co-authored-by: pavelsavara <271576+pavelsavara@users.noreply.github.com>
Copilot AI changed the title [WIP] [browser][docker] Fix MSBuild task host error with EmccCompile Fix IBuildEngine9.RequestCores returning 0 causing ReleaseCores(0) to throw in WASM/Mono build tasks Mar 18, 2026
Copilot AI requested a review from pavelsavara March 18, 2026 07:33
@pavelsavara
Copy link
Member

@copilot check when this code was really introduced and update "regression" section in the PR description

Copy link
Contributor Author

Copilot AI commented Mar 18, 2026

@copilot check when this code was really introduced and update "regression" section in the PR description

Traced the history:

So the root regression is .NET 9 (PR #104141). Updating the PR description now.

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

Defensive fix across WASM/Mono MSBuild tasks to avoid crashes and task-host failures when negotiating CPU cores via IBuildEngine9 in constrained or out-of-proc environments.

Changes:

  • Guard ReleaseCores(...) by only keeping be9 when RequestCores(...) returns a positive grant.
  • Broaden the RequestCores(...) exception handling to cover task-host callback failures (e.g., MSB5022 scenarios).
  • Apply the same pattern consistently across four tasks (EmccCompile, MonoAOTCompiler, ILStrip, EmitBundleBase).

Reviewed changes

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

File Description
src/tasks/WasmAppBuilder/EmccCompile.cs Prevents ReleaseCores(0) crash and avoids task-host callback failures around parallel emcc compilation.
src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs Applies the same RequestCores/ReleaseCores guarding to IL stripping parallelism.
src/tasks/MonoTargetsTasks/EmitBundleTask/EmitBundleBase.cs Applies the same defensive core-request logic to resource bundling parallelism.
src/tasks/AotCompilerTask/MonoAOTCompiler.cs Applies the same defensive core-request logic to AOT compilation parallelism.

Comment on lines +139 to +144
int requestedCores = be9.RequestCores(allowedParallelism);
if (requestedCores > 0)
allowedParallelism = requestedCores;
else
be9 = null;
}
Comment on lines +146 to 150
catch (Exception)
{
// RequestCores is not implemented in TaskHostFactory
// RequestCores is not implemented in TaskHostFactory, or IBuildEngine callbacks are not supported
be9 = null;
}
Comment on lines +82 to +87
int requestedCores = be9.RequestCores(allowedParallelism);
if (requestedCores > 0)
allowedParallelism = requestedCores;
else
be9 = null;
}
Comment on lines +89 to 93
catch (Exception)
{
// RequestCores is not implemented in TaskHostFactory
// RequestCores is not implemented in TaskHostFactory, or IBuildEngine callbacks are not supported
be9 = null;
}
Comment on lines +162 to +167
int requestedCores = be9.RequestCores(allowedParallelism);
if (requestedCores > 0)
allowedParallelism = requestedCores;
else
be9 = null;
}
Comment on lines +169 to 173
catch (Exception)
{
// RequestCores is not implemented in TaskHostFactory
// RequestCores is not implemented in TaskHostFactory, or IBuildEngine callbacks are not supported
be9 = null;
}
Comment on lines +549 to +554
int requestedCores = be9.RequestCores(allowedParallelism);
if (requestedCores > 0)
allowedParallelism = requestedCores;
else
be9 = null;
}
Comment on lines +556 to 560
catch (Exception)
{
// RequestCores is not implemented in TaskHostFactory
// RequestCores is not implemented in TaskHostFactory, or IBuildEngine callbacks are not supported
be9 = null;
}
@pavelsavara
Copy link
Member

Fixed by dotnet/msbuild#13345

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][docker] DisableParallelEmccCompile - MSB5022: The MSBuild task host does not support running tasks that perform IBuildEngine callbacks

3 participants