From acd9efd5edff4af7e5fe369a86a38b97d8d68d4a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 30 Aug 2026 18:05:14 +0000
Subject: [PATCH 1/2] Fix paket pack failing on conditional TargetFramework(s)
PropertyGroups (fixes #3799)
Closes #3799
getOutputDirectory evaluated TargetFramework/TargetFrameworks with an
empty Configuration/Platform property map, so conditional PropertyGroups
keyed on Configuration/Platform (e.g. Condition="'$(Configuration)'=='Release'")
were never matched and no target framework was found, causing:
'Unable to find Release output path node ... for any known platforms'.
Fix: evaluate TargetFramework/TargetFrameworks with the requested
Configuration and Platform values already available in getOutputDirectory,
via new getTargetFrameworkWithDefaults/getTargetFrameworksParsedWithDefaults
helpers that reuse the existing conditional-property evaluator.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../PaketConfigFiles/ProjectFile.fs | 28 ++++++++++++++++---
tests/Paket.Tests/Paket.Tests.fsproj | 1 +
tests/Paket.Tests/ProjectFile/OutputSpecs.fs | 9 ++++++
...WithConditionalTargetFrameworks.csprojtest | 15 ++++++++++
4 files changed, 49 insertions(+), 4 deletions(-)
create mode 100644 tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest
diff --git a/src/Paket.Core/PaketConfigFiles/ProjectFile.fs b/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
index c7fac7430c..eeff28f21f 100644
--- a/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
+++ b/src/Paket.Core/PaketConfigFiles/ProjectFile.fs
@@ -1069,6 +1069,20 @@ module ProjectFile =
|> Array.map (fun x -> x.Trim())
|> Array.toList
+ // Same as getTargetFramework/getTargetFrameworksParsed above but evaluates conditional
+ // PropertyGroups (e.g. `Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"`)
+ // using the given Configuration/Platform, instead of an empty property map.
+ let getTargetFrameworkWithDefaults defaultProperties (project:ProjectFile) =
+ getPropertyWithDefaults "TargetFramework" defaultProperties project
+
+ let getTargetFrameworksParsedWithDefaults defaultProperties (project:ProjectFile) =
+ getPropertyWithDefaults "TargetFrameworks" defaultProperties project
+ |> Option.map (fun x -> x.Split([|';'|],StringSplitOptions.RemoveEmptyEntries))
+ |> Option.toArray
+ |> Array.concat
+ |> Array.map (fun x -> x.Trim())
+ |> Array.toList
+
let getToolsVersion (project:ProjectFile) =
let adjustIfWeHaveSDK v =
try
@@ -1622,22 +1636,28 @@ module ProjectFile =
sprintf "%s.%s" assemblyName ending
let getOutputDirectory buildConfiguration buildPlatform (targetProfile : TargetProfile option) (project:ProjectFile) =
+ // Some projects put TargetFramework(s) inside a conditional PropertyGroup keyed on
+ // Configuration/Platform (e.g. `Condition="'$(Configuration)'=='Release'"`), so we must
+ // evaluate the property map with the requested Configuration/Platform, not an empty one,
+ // or the frameworks won't be found at all (see issue #3799).
+ let defaultProperties =
+ Map.ofList [("Configuration", buildConfiguration); ("Platform", buildPlatform)]
let targetFramework =
match targetProfile with
| Some targetProfile ->
let targetProfile = targetProfile.ToString()
- match getTargetFramework project with
+ match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> if x = targetProfile then x else ""
| None ->
- let parsedTargetFrameworks = getTargetFrameworksParsed project
+ let parsedTargetFrameworks = getTargetFrameworksParsedWithDefaults defaultProperties project
match List.tryFind ((=) targetProfile) parsedTargetFrameworks with
| Some x -> x
| None -> ""
| None ->
- match getTargetFramework project with
+ match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> x
| None ->
- match getTargetFrameworksParsed project with
+ match getTargetFrameworksParsedWithDefaults defaultProperties project with
| fwk :: _ -> fwk
| [] -> ""
diff --git a/tests/Paket.Tests/Paket.Tests.fsproj b/tests/Paket.Tests/Paket.Tests.fsproj
index 0ff0e05548..039f50cf9c 100644
--- a/tests/Paket.Tests/Paket.Tests.fsproj
+++ b/tests/Paket.Tests/Paket.Tests.fsproj
@@ -130,6 +130,7 @@
+
diff --git a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
index 88b95a32ed..9c567a77c2 100644
--- a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
+++ b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
@@ -103,6 +103,15 @@ let ``should detect output path for netsdk with outputPath and appendTargetFrame
let expected = (System.IO.Path.Combine(@"bin", configuration,"netstandard1.4_bin") |> normalizePath)
outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+[]
+let ``should detect output path for netsdk with conditional target frameworks csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest").Value
+ // Should not throw "Unable to find output path node" (see issue #3799)
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ outPath |> shouldNotEqual ""
+
[]
let ``should detect framework profile for ProjectWithConditions file`` () =
ensureDir ()
diff --git a/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest
new file mode 100644
index 0000000000..23350487da
--- /dev/null
+++ b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest
@@ -0,0 +1,15 @@
+
+
+
+ TestPaket
+ netstandard2.0
+
+
+
+ netstandard2.0;net45
+
+
+
+ netstandard2.0;net45;net47
+
+
From cc8ccab78a2c6b1f71034f1d760aac16f71c9f39 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 1 Sep 2026 16:05:03 +0000
Subject: [PATCH 2/2] Expand test matrix for conditional TargetFramework(s) fix
(#3799)
- Add MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest fixture
that reproduces the exact original issue shape (no unconditional
TargetFramework/TargetFrameworks fallback element).
- Add case-insensitive configuration coverage (dEbUg/rElEaSe) for the
conditional-frameworks fixture.
- Add a test asserting the correct default framework (first listed) is
picked per configuration.
- Add a test asserting GetOutputDirectory resolves the output path for a
specific requested TargetProfile (net45) inside conditional PropertyGroups.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
tests/Paket.Tests/Paket.Tests.fsproj | 1 +
tests/Paket.Tests/ProjectFile/OutputSpecs.fs | 35 ++++++++++++++++++-
...ConditionalTargetFrameworksOnly.csprojtest | 10 ++++++
3 files changed, 45 insertions(+), 1 deletion(-)
create mode 100644 tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest
diff --git a/tests/Paket.Tests/Paket.Tests.fsproj b/tests/Paket.Tests/Paket.Tests.fsproj
index 039f50cf9c..2beb860531 100644
--- a/tests/Paket.Tests/Paket.Tests.fsproj
+++ b/tests/Paket.Tests/Paket.Tests.fsproj
@@ -131,6 +131,7 @@
+
diff --git a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
index 9c567a77c2..7ab8f22034 100644
--- a/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
+++ b/tests/Paket.Tests/ProjectFile/OutputSpecs.fs
@@ -105,13 +105,46 @@ let ``should detect output path for netsdk with outputPath and appendTargetFrame
[]
let ``should detect output path for netsdk with conditional target frameworks csproj file``
- ([] configuration) =
+ ([] configuration) =
ensureDir ()
let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest").Value
// Should not throw "Unable to find output path node" (see issue #3799)
let outPath = projectFile.GetOutputDirectory configuration "" None
outPath |> shouldNotEqual ""
+[]
+let ``should detect output path for netsdk with only conditional target frameworks (no unconditional fallback) csproj file``
+ ([] configuration) =
+ ensureDir ()
+ // Reproduces the exact shape from issue #3799: no unconditional TargetFramework/TargetFrameworks
+ // element exists at all, only Configuration-conditioned PropertyGroups.
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ outPath |> shouldNotEqual ""
+
+[]
+let ``should pick the conditional target frameworks matching the requested configuration for netsdk csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let outPath = projectFile.GetOutputDirectory configuration "" None
+ // Debug config only lists netstandard2.0;net45, Release additionally lists net47;
+ // the first framework in each list is netstandard2.0, and it should be selected as the default.
+ let expected = (System.IO.Path.Combine(@"bin", configuration, "netstandard2.0") |> normalizePath)
+ outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+
+[]
+let ``should detect output path for a specific target profile in a conditional target frameworks csproj file``
+ ([] configuration) =
+ ensureDir ()
+ let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
+ let targetProfile =
+ FrameworkDetection.internalExtract "net45"
+ |> Option.map TargetProfile.SinglePlatform
+ let outPath = projectFile.GetOutputDirectory configuration "" targetProfile
+ let expected = (System.IO.Path.Combine(@"bin", configuration, "net45") |> normalizePath)
+ outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())
+
[]
let ``should detect framework profile for ProjectWithConditions file`` () =
ensureDir ()
diff --git a/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest
new file mode 100644
index 0000000000..7b87c3d03c
--- /dev/null
+++ b/tests/Paket.Tests/ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0;net45
+
+
+
+ netstandard2.0;net45;net47
+
+