Skip to content

MSBuild property values containing '/dotnet' are silently dropped, causing MSB1009 #2797

@chris-peterson

Description

@chris-peterson

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions