Steps to Reproduce
Any dotnet msbuild invocation where a -p: property value ends with /dotnet:
mkdir repro && cd repro
dotnet new console
dotnet msbuild -p:MyProp=something/dotnet
This also reproduces via dotnet build, dotnet publish, etc.
Expected Behavior
MSBuild parses -p:MyProp=something/dotnet as property MyProp with value something/dotnet and proceeds with the build.
Actual Behavior
MSBUILD : error MSB1009: Project file does not exist.
Switch: MyProp=something/dotnet
The -p: option is silently rejected. The property name and value are treated as an unmatched argument, and MSBuild cannot find a project file.
Only the suffix /dotnet triggers the bug. Other suffixes work correctly:
dotnet msbuild -p:MyProp=something/other # works
dotnet msbuild -p:MyProp=something/dotnet # MSB1009
Invoking MSBuild.dll directly (bypassing the dotnet CLI) works:
dotnet exec "$(dotnet --list-sdks | tail -1 | sed 's/.* \[\(.*\)\]/\1/')"/MSBuild.dll -p:MyProp=something/dotnet
# works
Analysis
PR dotnet/sdk#49526 ("Improve MSBuild argument parsing and tracking") introduced MSBuildArgs.AnalyzeMSBuildArguments, which re-parses forwarded MSBuild
arguments through a synthetic System.CommandLine command to extract structured properties, targets, and verbosity for restore optimization.
The synthetic command is named "dotnet":
// src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildArgs.cs, line 105
var fakeCommand = new System.CommandLine.Command("dotnet");
System.CommandLine treats /<command-name> within option values as a reference to the command itself. Since the command is named "dotnet", any
/p: value containing the substring /dotnet causes the parser to reject the entire token as unmatched. The property never reaches MSBuild.
Proposed fix: rename the synthetic command to a name that cannot collide with property values:
var fakeCommand = new System.CommandLine.Command("_");
I confirmed this resolves the issue in an isolated System.CommandLine repro — only the command's own name triggers the bug.
Versions & Configurations
Working:
- SDK 9.0.100 (MSBuild 17.12.7) — predates
MSBuildArgs.AnalyzeMSBuildArguments
Broken:
- SDK 10.0.100 (MSBuild 18.0.2)
- SDK 10.0.201 (MSBuild 18.3.0)
Workaround: export the property as an environment variable instead of passing via /p:. MSBuild reads environment variables as properties.
export MyProp=something/dotnet
dotnet msbuild
Steps to Reproduce
Any
dotnet msbuildinvocation where a-p:property value ends with/dotnet:This also reproduces via
dotnet build,dotnet publish, etc.Expected Behavior
MSBuild parses
-p:MyProp=something/dotnetas propertyMyPropwith valuesomething/dotnetand proceeds with the build.Actual Behavior
The
-p:option is silently rejected. The property name and value are treated as an unmatched argument, and MSBuild cannot find a project file.Only the suffix
/dotnettriggers the bug. Other suffixes work correctly:Invoking MSBuild.dll directly (bypassing the dotnet CLI) works:
Analysis
PR dotnet/sdk#49526 ("Improve MSBuild argument parsing and tracking") introduced
MSBuildArgs.AnalyzeMSBuildArguments, which re-parses forwarded MSBuildarguments through a synthetic
System.CommandLinecommand to extract structured properties, targets, and verbosity for restore optimization.The synthetic command is named
"dotnet":System.CommandLinetreats/<command-name>within option values as a reference to the command itself. Since the command is named"dotnet", any/p:value containing the substring/dotnetcauses the parser to reject the entire token as unmatched. The property never reaches MSBuild.Proposed fix: rename the synthetic command to a name that cannot collide with property values:
I confirmed this resolves the issue in an isolated
System.CommandLinerepro — only the command's own name triggers the bug.Versions & Configurations
Working:
MSBuildArgs.AnalyzeMSBuildArgumentsBroken:
Workaround: export the property as an environment variable instead of passing via
/p:. MSBuild reads environment variables as properties.export MyProp=something/dotnet dotnet msbuild