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 into
mainfrom
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 into
mainfrom
copilot/disable-parallel-emcc-compile

Conversation

Copy link
Copy Markdown
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
Copy Markdown
Member

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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Member

Fixed by dotnet/msbuild#13345

@jkotas jkotas deleted the copilot/disable-parallel-emcc-compile branch May 22, 2026 17:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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