Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 17, 2025

Summary

This PR adds a clear error message (MSB4233) when users try to use tasks with Runtime="NET" on MSBuild 17.14 (.NET Framework), which doesn't support .NET runtime tasks.

Changes

  • Added check in NodeProviderOutOfProcTaskHost.AcquireAndSetUpHost() to detect HandshakeOptions.NET flag
  • Throws InvalidProjectFileException with clear error message (MSB4233) before attempting to launch task host
  • Error message includes task name, assembly location, and guidance about required MSBuild version
  • Wrapped in #if NETFRAMEWORK since .NET Core/5+ builds (18.0+) support .NET runtime tasks
  • Added end-to-end tests for both BuildManager API and MSBuild CLI
  • All nullable reference warnings resolved

Testing

  • End-to-end test for BuildManager API verifies MSB4233 error
  • End-to-end test for MSBuild CLI verifies MSB4233 error
  • Tests use WindowsFullFrameworkOnlyFact and will run in CI on Windows

Fixes #12661

Original prompt

This section details on the original issue you should resolve

<issue_title>VS 17.14 should give a clearer error when trying to launch .NET Tasks</issue_title>
<issue_description>### Issue Description

In 18.0 we lit up support for Tasks declared with Runtime="NET" - but MSBuild Task Authors bulk-updating their UsingTasks to specify this Runtime may not give good error experiences to end users running those tasks on older VS versions.

Steps to Reproduce

Create a .NET (not Framework) Task with `Runtime="NET" in its UsingTask and attempt to run it from a vs17.14 version of MSBuild.exe.

Expected Behavior

The build (not evaluation) should fail at run-time with a clear error along the lines of:

The Task {TaskName} was specified to load with the .NET Runtime, but this version of MSBuild does not support loading Tasks with that Runtime. To load .NET Tasks, MSBuild.exe 18.0 or Visual Studio 2026 must be used.

Actual Behavior

The build fails at run-time with the following error:

System.AggregateException: One or more errors occurred. ---> Microsoft.Build.Exceptions.BuildAbortedException: Build was canceled.
        MSBuild.exe could not be launched as a child node as it could not be found at the location "C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64\MSBuild.dll". If necessary, specify the correct location in the BuildParameters, or with the MSBUILD_EXE_PATH environment variable.
  at Microsoft.Build.BackEnd.NodeLauncher.StartInternal(String msbuildLocation, String commandLineArgs)
  at Microsoft.Build.BackEnd.NodeLauncher.DisableMSBuildServer(Func`1 func)
  at Microsoft.Build.BackEnd.NodeProviderOutOfProcBase.<>c__DisplayClass14_0.<GetNodes>g__StartNewNode|2(Int32 nodeId)
  at Microsoft.Build.BackEnd.NodeProviderOutOfProcBase.<>c__DisplayClass14_0.<GetNodes>b__0(Int32 nodeId)

Analysis

We don't want to fail at evaluation time, because this would break clients pretty badly. Instead, we should fail when trying to execute the mismatched Task. This means I think one of two places:

  • task host node creation (NodeProviderOutOfProcBase.AcquireAndSetUpHost), or
  • TaskHostTask creation (which internally calls NodeProviderOutOfProcBase.AcquireAndSetUpHost)
    • TaskHostTask's constructor, or
    • AssemblyTaskFactory.CreateTaskInstance

There may be more options, these are just the two that stand out to me.

In any case, we need additional test cases to show the behavior of throwing the new exception when a NET-Runtime Task is loaded from .NET Framework MSBuild. Ideally the tests would show the behavior being triggered both from MSBuild.exe invocations directly and from usage of the MSBuild APIs.

Versions & Configurations

No response</issue_description>

<agent_instructions>Try to keep the changes as minimal as possible because we have a high quality bar to meet for this change to be accepted.</agent_instructions>

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

@rainersigwald Let's try switching to detecting `Runtime="NET"` in `Microsoft.Build.BackEnd.NodeProviderOutOfProcTaskHost.AcquireAndSetUpHost` and throwing an `InvalidProjectException` and see what the UX of that is.

Fixes #12661


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

@dotnet-policy-service
Copy link
Contributor

Hello @@copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo.

Copilot AI changed the title [WIP] Improve error message for .NET Tasks in VS 17.14 Add clear error message (MSB4233) for .NET runtime tasks on MSBuild 17.14 Oct 17, 2025
Copilot AI requested a review from baronfel October 17, 2025 15:52
Copilot finished work on behalf of baronfel October 17, 2025 15:52
Copy link
Member

@baronfel baronfel left a comment

Choose a reason for hiding this comment

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

@copilot some things to clean up

Comment on lines 93 to 101
exception.ProjectFile.ShouldBe(projectFile);
exception.LineNumber.ShouldBe(lineNumber);
exception.ColumnNumber.ShouldBe(columnNumber);
exception.ErrorCode.ShouldBe("MSB4233");
exception.Message.ShouldContain(taskName);
exception.Message.ShouldContain(taskLocation);
exception.Message.ShouldContain(".NET");
exception.Message.ShouldContain("MSBuild 18.0");
exception.Message.ShouldContain("Visual Studio 2026");
Copy link
Member

Choose a reason for hiding this comment

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

for all the test assertions in this file, only the error code, task name, and task location are really important. the rest is synthetic data that's irrelevant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simplified the test assertions to only verify the error code (MSB4233), task name, and task location. The other assertions (project file, line number, column number) were testing synthetic data that isn't relevant to this scenario. (commit: 9b5c9eb)

Comment on lines 495 to 505
throw new Exceptions.InvalidProjectFileException(
configuration.ProjectFileOfTask,
configuration.LineNumberOfTask,
configuration.ColumnNumberOfTask,
0,
0,
ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TaskRuntimeNET", configuration.TaskName, configuration.TaskLocation),
null,
null,
null);
}
Copy link
Member

Choose a reason for hiding this comment

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

we shouldn't be throwing the exception directly - use the helper functions that the rest of the codebase uses for throwing InvalidProjectFile errors

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to use ProjectFileErrorUtilities.ThrowInvalidProjectFile helper function instead of directly throwing the exception. This follows the pattern used throughout the codebase and properly constructs the BuildEventFileInfo. (commit: 9b5c9eb)

</data>
<data name="TaskRuntimeNET" xml:space="preserve">
<value>MSB4233: The task "{0}" from assembly "{1}" was specified to load with the .NET runtime, but this version of MSBuild does not support loading tasks with that runtime. To load .NET tasks, MSBuild 18.0 or Visual Studio 2026 must be used.</value>
<comment>{StrBegin="MSB4233: "}LOCALIZATION: .NET should not be localized.</comment>
Copy link
Member

Choose a reason for hiding this comment

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

The {Locked="<content goes here>"} syntax can be used to communicated to localizers that specific terms should not be translated. Use it for the .NET, MSBuild and Visual Studio 2026 tokens.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added {Locked=".NET"}{Locked="MSBuild"}{Locked="Visual Studio 2026"} to the resource string comment to ensure these terms are not translated by localizers. (commit: 9b5c9eb)

Copilot AI requested a review from baronfel October 17, 2025 16:04
Copilot finished work on behalf of baronfel October 17, 2025 16:04
@baronfel
Copy link
Member

@copilot please also add end-to-end tests for the MSBuild CLI and MSBuild API usage that load a Project that consumes a .NET Runtime Task and fails appropriately. You won't be able to run these because they are windows-only, so follow existing patterns for Framework-only end-to-end tests and we can let CI try to verify them.

Copy link
Contributor Author

Copilot AI commented Oct 17, 2025

@copilot please also add end-to-end tests for the MSBuild CLI and MSBuild API usage that load a Project that consumes a .NET Runtime Task and fails appropriately. You won't be able to run these becaus...

Added end-to-end tests for both BuildManager API and MSBuild CLI usage:

  • DotNetRuntimeTask_EndToEnd_Tests.cs tests BuildManager.Build() and ProjectInstance.Build() scenarios
  • DotNetRuntimeTask_CLI_Tests.cs tests MSBuild.exe command line execution
  • Tests verify MSB4233 error is shown with clear message about .NET runtime not being supported
  • Tests use WindowsFullFrameworkOnlyFact attribute following existing patterns
  • Tests will run in CI on Windows to validate the error handling

(commit: 4c8c0d7)

Copilot finished work on behalf of baronfel October 17, 2025 16:16
@baronfel
Copy link
Member

@copilot compilation is failing on the Windows Full Release pipeline because the HandshakeOptions type isn't visible:

src\Build.UnitTests\BackEnd\NodeProviderOutOfProcTaskHost_Tests.cs(57,13): error CS0246: (NETCORE_ENGINEERING_TELEMETRY=Build) The type or namespace name 'HandshakeOptions' could not be found (are you missing a using directive or an assembly reference?)

If this type actually visible when targeting .NET Framework?

Copy link
Contributor Author

Copilot AI commented Oct 17, 2025

@copilot compilation is failing on the Windows Full Release pipeline because the HandshakeOptions type isn't visible:

src\Build.UnitTests\BackEnd\NodeProviderOutOfProcTaskHost_Tests.cs(57,13): ...

Yes, HandshakeOptions is visible when targeting .NET Framework. It's an internal enum in Microsoft.Build.Shared that's exposed to Microsoft.Build.Engine.UnitTests via InternalsVisibleTo.

The code at line 57 is inside a #if NETFRAMEWORK block (added in commit 78985e2), so it should only compile for .NET Framework targets. The error mentioning (NETCORE_ENGINEERING_TELEMETRY=Build) suggests the CI is compiling for .NET Core, where the #if should exclude that code.

Can you confirm which commit SHA the failing build is using? The #if NETFRAMEWORK guards should be present in commit b48a64d and later.

Copilot finished work on behalf of baronfel October 17, 2025 16:34
@baronfel
Copy link
Member

@copilot remove the NodeProviderOutOfProcTaskHost_Tests - they've served their purpose and we can't directly use the HandshakeOptions type.

Copy link
Contributor Author

Copilot AI commented Oct 17, 2025

@copilot remove the NodeProviderOutOfProcTaskHost_Tests - they've served their purpose and we can't directly use the HandshakeOptions type.

Removed NodeProviderOutOfProcTaskHost_Tests.cs. The end-to-end tests in DotNetRuntimeTask_EndToEnd_Tests.cs and DotNetRuntimeTask_CLI_Tests.cs provide sufficient coverage for the MSB4233 error without requiring direct access to internal types. (commit: e8c9f2a)

@baronfel baronfel dismissed their stale review October 17, 2025 20:27

It's me!

Copilot finished work on behalf of baronfel October 17, 2025 20:27
@baronfel baronfel requested review from a team and rainersigwald October 17, 2025 21:31
@baronfel baronfel marked this pull request as ready for review October 17, 2025 21:31
Copilot AI review requested due to automatic review settings October 17, 2025 21:31
@baronfel
Copy link
Member

This is ready for review now - once reviews are good we'll want to take this to VS QB

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

Adds a specific error (MSB4233) when a task declares Runtime="NET" on MSBuild 17.14 (.NET Framework build) to replace a previously confusing failure, plus tests validating behavior and localized resource entries.

  • Introduces early runtime check in NodeProviderOutOfProcTaskHost.AcquireAndSetUpHost to throw a clear InvalidProjectFile error.
  • Adds new resource string (TaskRuntimeNET) with localization placeholders.
  • Provides end-to-end API and CLI tests for both failing (.NET runtime task) and succeeding (normal task) scenarios.

Reviewed Changes

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

Show a summary per file
File Description
src/MSBuild.UnitTests/DotNetRuntimeTask_CLI_Tests.cs Adds CLI tests verifying MSB4233 appears for Runtime="NET" and normal tasks still succeed.
src/Build/Resources/xlf/Strings.zh-Hant.xlf Adds localized (untranslated initial) entry for new MSB4233 error.
src/Build/Resources/xlf/Strings.zh-Hans.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.tr.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.ru.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.pt-BR.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.pl.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.ko.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.ja.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.it.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.fr.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.es.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.de.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/xlf/Strings.cs.xlf Adds localized entry for MSB4233 error.
src/Build/Resources/Strings.resx Defines the new TaskRuntimeNET resource string and localization locking comments.
src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs Adds runtime flag check and throws MSB4233 before host launch.
src/Build.UnitTests/BackEnd/DotNetRuntimeTask_EndToEnd_Tests.cs Adds BuildManager and ProjectInstance API tests for MSB4233 behavior and success path.

Copilot AI and others added 10 commits October 20, 2025 10:14
- Added MSB4233 error code reference in comment
- Clarified that .NET Core/5+ MSBuild (18.0+) supports .NET runtime tasks
- Explained that this prevents confusing "MSBuild.dll not found" error

Co-authored-by: baronfel <[email protected]>
- Simplify test assertions to only check error code, task name, and task location
- Use ProjectFileErrorUtilities.ThrowInvalidProjectFile helper instead of direct exception throw
- Add Locked syntax for .NET, MSBuild, and Visual Studio 2026 in resource string

Co-authored-by: baronfel <[email protected]>
- Add BuildManager API tests in DotNetRuntimeTask_EndToEnd_Tests.cs
- Add MSBuild CLI tests in DotNetRuntimeTask_CLI_Tests.cs
- Tests verify MSB4233 error is shown with clear message
- Tests use WindowsFullFrameworkOnlyFact since feature is Framework-only
- Tests follow existing patterns and will run in CI on Windows

Co-authored-by: baronfel <[email protected]>
The unit tests in NodeProviderOutOfProcTaskHost_Tests.cs directly used the internal HandshakeOptions type, which caused compilation issues in multi-targeting scenarios. The end-to-end tests in DotNetRuntimeTask_EndToEnd_Tests.cs and DotNetRuntimeTask_CLI_Tests.cs provide sufficient coverage for the MSB4233 error handling without requiring direct access to internal types.

Co-authored-by: baronfel <[email protected]>
Remove #nullable disable directive from DotNetRuntimeTask_EndToEnd_Tests.cs and DotNetRuntimeTask_CLI_Tests.cs to enable nullable reference type checking.

Co-authored-by: baronfel <[email protected]>
- Update comment in NodeProviderOutOfProcTaskHost.cs to clarify version (18.0+)
- Remove redundant tests that don't add value:
  - BuildManager_WithoutDotNetRuntime_Succeeds
  - ProjectInstance_WithDotNetRuntimeTask_ShowsClearError
  - MSBuildCLI_WithoutDotNetRuntime_Succeeds
- Keep only the essential test that verifies MSB4233 error for Runtime="NET" tasks

Co-authored-by: baronfel <[email protected]>
- Remove custom task building code from MSBuildCLI_WithDotNetRuntimeTask_ShowsClearError
- Use ProcessIdTask from Microsoft.Build.Engine.UnitTests assembly (same as EndToEnd test)
- Remove unused System.IO using statement
- Test is now simpler, faster, and consistent with the EndToEnd test

Co-authored-by: rainersigwald <[email protected]>
- Change UsingTask to use AssemblyFile with the actual path to ProcessIdTask assembly
- Get path using typeof(ProcessIdTask).Assembly.Location
- This ensures MSBuild CLI can locate the task without relying on assembly resolution
- Add System using statement for typeof

Co-authored-by: rainersigwald <[email protected]>
- Remove direct typeof(ProcessIdTask) reference that caused CS0234 error
- Construct path to Microsoft.Build.Engine.UnitTests.dll dynamically at runtime
- Use Assembly.GetExecutingAssembly().Location and Path.Combine
- Add necessary using statements (System.IO, System.Reflection)
- This avoids compile-time dependency on ProcessIdTask type

Co-authored-by: YuliiaKovalova <[email protected]>
@baronfel baronfel force-pushed the copilot/improve-error-message-for-net-tasks branch from f9d9b3e to e9715d0 Compare October 20, 2025 15:14
@YuliiaKovalova YuliiaKovalova self-assigned this Nov 3, 2025
@YuliiaKovalova
Copy link
Member

@copilot fix the issue
src\Build.UnitTests\BackEnd\DotNetRuntimeTask_EndToEnd_Tests.cs(68,17): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'actual' in 'void ShouldBeStringTestExtensions.ShouldContain(

…al variable

Extract logger.Errors[0].Message to a local variable before calling ShouldContain to resolve CS8604 nullable reference warning. The variable assignment ensures the null-state analysis understands the value is not null.

Co-authored-by: YuliiaKovalova <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 6, 2025

@copilot fix the issue
src\Build.UnitTests\BackEnd\DotNetRuntimeTask_EndToEnd_Tests.cs(68,17): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'act...

Fixed the nullable reference warning by extracting logger.Errors[0].Message to a local variable before calling ShouldContain. This resolves the CS8604 error. (commit: cd458ac)

Copilot finished work on behalf of YuliiaKovalova November 6, 2025 16:20
@YuliiaKovalova
Copy link
Member

@copilot I see other issues
{6BAFB05D-D88A-4792-8792-710F53A75ECB}

- Add null-forgiving operator and ShouldNotBeNull assertion for error message
- This resolves CS8600 and CS8604 nullable reference warnings
- Tests now properly handle nullable string from logger.Errors[0].Message

Co-authored-by: YuliiaKovalova <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 6, 2025

@copilot I see other issues
{6BAFB05D-D88A-4792-8792-710F53A75ECB}

Fixed the nullable reference warnings by adding ShouldNotBeNull() assertion and using nullable type annotation. (commit: 0d76afa)

Copilot finished work on behalf of YuliiaKovalova November 6, 2025 16:39
@YuliiaKovalova
Copy link
Member

@copilot the test fails with
Executing [D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\MSBuild.exe "C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj" /t:TestTask]
==== OUTPUT ====
MSBuild version 17.14.31+3657660c4 for .NET Framework
Build started 11/6/2025 5:10:41 PM.

Project "C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj" on node 1 (TestTask target(s)).
C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj(5,9): error MSB4062: The "ProcessIdTask" task could not be loaded from the assembly D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\Microsoft.Build.Engine.UnitTests.dll. Could not load file or assembly 'file:///D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\Microsoft.Build.Engine.UnitTests.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
Done Building Project "C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj" (TestTask target(s)) -- FAILED.

Build FAILED.

"C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj" (TestTask target) (1) ->
(TestTask target) ->
C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\Temporary138a2b57c7794ffe8000debafd185ea1\test.proj(5,9): error MSB4062: The "ProcessIdTask" task could not be loaded from the assembly D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\Microsoft.Build.Engine.UnitTests.dll. Could not load file or assembly 'file:///D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\Microsoft.Build.Engine.UnitTests.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

0 Warning(s)
1 Error(s)

Time Elapsed 00:00:00.43
Process ID is 7960

==============

The test was failing because it tried to load the assembly from the wrong directory. Now it properly navigates to the sibling Microsoft.Build.Engine.UnitTests output directory to find the DLL.

Co-authored-by: YuliiaKovalova <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 6, 2025

@copilot the test fails with
Executing [D:\a\1\s\artifacts\bin\Microsoft.Build.CommandLine.UnitTests\Debug\net472\MSBuild.exe "C:\Users\VssAdministrator\AppData\Local\Temp\wcxc1rpv.cs3\MSBuildTemp\T...

Fixed the assembly path construction in the CLI test. The test was looking for Microsoft.Build.Engine.UnitTests.dll in the wrong directory. Now it properly navigates to the sibling output directory: ../Microsoft.Build.Engine.UnitTests/net472/Microsoft.Build.Engine.UnitTests.dll (commit: dd7467d)

Copilot finished work on behalf of YuliiaKovalova November 6, 2025 20:28
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.

4 participants