Paket icon indicating copy to clipboard operation
Paket copied to clipboard

Warning NU1510: PackageReference ***.*** will not be pruned. Consider removing this package from your dependencies, as it is likely unnecessary.

Open aklefdal opened this issue 2 months ago • 3 comments

I get quite a few of these warnings when doing dotnet restore when running paket 10.0.0-alpha011 on a net10.0 project.

I guess this is the result of some changes in the .NET 10 SDK, which really aren't a problem. I still want to understand why I get them, and whether we can do some changes i how Paket works to avoid these watnings.

Also mentioned in the .NET 10 issue (#4296 ):

  • https://github.com/fsprojects/Paket/issues/4296#issuecomment-3536734036
  • https://github.com/fsprojects/Paket/issues/4296#issuecomment-3547114583

aklefdal avatar Nov 19 '25 08:11 aklefdal

I asked Copilot and it came up with quite a useful summary:

Copilot Answer

Here’s what’s going on with NU1510 in your scenario.

What NU1510 means

NU1510: PackageReference ***.*** will not be pruned. Consider removing this package from your dependencies, as it is likely unnecessary.

This is a NuGet / SDK warning, not a Paket warning. It is emitted during dotnet restore when:

  • You have a PackageReference that ends up not contributing any compile/runtime assets to the final graph (e.g., all of its assemblies are incompatible with your target framework, or it’s fully transitive-only / design-time-only), and
  • The restore logic decides that the package is effectively unused for the target frameworks you’re building.

In .NET SDK 10.0, NuGet has become more aggressive and explicit about pruning “unused” references from the effective graph, and it now warns you when a reference is pruned or ignored.

Why you see this with .NET 10.0 + Paket

With Paket 10.0.0-alpha011 on a net10.0 project, you’re running into a combination of:

  1. New SDK behavior in .NET 10

    • The .NET 10 SDK has evolved the way it:
      • Evaluates compatibility (TFM support, lib/, ref/, runtimes/ folders, buildTransitive, etc.).
      • Prunes packages that are determined to be unused/irrelevant to the final graph.
    • The SDK/NuGet now emits NU1510 when it concludes a package is never actually used for your project’s TFMs.
  2. How Paket integrates with dotnet restore

    • Paket ultimately generates MSBuild items / PackageReference equivalents (directly or indirectly via paket.references translation).
    • Some of these references might be:
      • Only needed transitively (i.e., you pinned them explicitly in Paket to control versions, but the SDK sees them as redundant).
      • For older target frameworks (e.g., they only have lib/netstandard2.0, which might be considered irrelevant or not chosen for net10.0 if better assets exist from other packages).
      • Analyzers, tooling, or design-time packages that no longer contribute usable assets for net10.0.

    When dotnet restore processes the resulting PackageReferences for net10.0, it decides some of them are not needed and warns with NU1510.

  3. Net 10.0 & evolving TFM support in packages

    • Many packages today ship assets for netstandard2.0, net6.0, net7.0, etc., but not explicitly net10.0.
    • The SDK uses a TFM compatibility matrix. In .NET 10.0, some packages:
      • Are considered not compatible enough to contribute meaningful assets to net10.0, or
      • Are overshadowed by other, more specific assets provided by other dependencies.
    • Result: the package is effectively “dead weight” for this TFM, triggering NU1510.

So, why this shows up now (compared to older SDKs)

Older SDKs:

  • Either didn’t perform as strict pruning, or
  • Didn’t surface this specific diagnostic (NU1510) as a warning.

Starting with the newer .NET SDKs (10.0 in your case):

  • The restore phase has stricter logic for unused or prunable references.
  • That logic is now surfaced prominently via NU1510.

Is it actually a problem?

Often, no, it’s not a functional problem:

  • Your app will still build and run.
  • The warning is telling you:
    • “This package does not contribute anything to the build for net10.0.”
    • “You can probably remove this reference, clean up your dependency graph, and things will behave the same.”

However, it’s still useful to:

  • Identify packages that are truly obsolete/unnecessary.
  • Catch incorrect assumptions about what packages are actually doing for your net10.0 build.

Why Paket specifically can trigger more of these

A few common Paket patterns that tend to surface more NU1510 warnings under newer SDKs:

  1. Pinning transitive dependencies as direct dependencies

    • In Paket you might have:
      nuget A
      nuget B
      nuget C
      
      even though C is already brought in by A or B.
    • For net10.0, C might end up fully unused, so NuGet raises NU1510.
  2. Legacy or multi-TFM workaround dependencies

    • Dependencies originally added to satisfy older TFMs (like net461, netcoreapp3.1, etc.) that are no longer relevant for net10.0.
    • The SDK sees they don’t provide any viable assets and prunes them.
  3. Packages used only for tooling / design-time / build-time where assets are ignored

    • Some packages were historically used for MSBuild props/targets or design-time tooling.
    • If the SDK decides their assets no longer match the current TFM or are no longer used in the standard pipeline, it can mark them unused.

What you can/should do

At the project/package level:

  1. Inspect a few of the packages mentioned in NU1510:

    • Check the NuGet page or .nuspec / lib / ref folders.
    • See which TFMs they support and if they have any assets that make sense for net10.0.
  2. If a package truly is no longer needed:

    • Remove it from:
      • paket.dependencies
      • paket.references for that project
    • Run paket install / paket update and then dotnet restore to verify.
  3. If a package is meant to be there (e.g., analyzers, build-only tools), and it’s harmless:

    • You can consider:
      • Suppressing NU1510 at the project level via .csproj:
        <PropertyGroup>
          <NoWarn>$(NoWarn);NU1510</NoWarn>
        </PropertyGroup>
        
      • Or selectively suppressing it per package (requires more fine-grained MSBuild configuration).

At the Paket side (what might be worth discussing in the issue):

  • Detecting and optionally not emitting certain redundant PackageReferences for target frameworks where the package has no meaningful assets.
  • Providing an analysis mode / diagnostics:
    • “These packages appear unused for TFM net10.0; you can likely remove them.”
  • Documenting that:
    • With newer .NET SDKs, NU1510 warnings are expected if your paket.references contains packages that are only relevant to other TFMs or are fully transitive.

Direct answer to your question

You see NU1510 with the latest .NET 10.0 SDK because:

  • The .NET 10.0 restore logic is stricter and more explicit about unused or prunable PackageReferences.
  • Some packages that Paket is feeding into the project for net10.0 are not contributing any compile/runtime/build assets for that TFM.
  • The SDK therefore decides they won’t be pruned into the graph (i.e., effectively ignored) and warns you to remove them as likely unnecessary.

If you share a concrete example of one of the warned packages (name + its .nuspec/TFMs), I can walk through that specific case and show exactly why net10.0 considers it unused.

halcwb avatar Nov 19 '25 09:11 halcwb

https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#prunepackagereference

For transitive packages, meaning dependencies of other packages or projects, the packages are not downloaded and do not appear in any of the outputs of NuGet.

...

The benefits of package pruning are two-fold:

  • Performance benefits, by virtue of reducing the number of packages within a dependency graph
  • Reduction of false positives by component scanners such as NuGetAudit

Pruning is particularly valuable when auditing packages with NuGetAuditMode set to all. If you are using .NET 9, we recommend you try out pruning by setting RestoreEnablePackagePruning to true.

So a build time optimization to not download, parse and continue the dependency tree for stuff that is included anyway (all dependencies of a runtime include library, will naturally also be runtime included libraries)?

I'm not familiar with the audit stuff as to how much trouble the "false positives" are.

For a .NET10 project I got a bunch of NU1510 on, the DLLs in question were not copied to output, so its not so bad as including a ton of extra files in the final build, far as I can tell.


I guess in the context of Paket the equivalent performance optimization would also actually to be eliminate them at paket install time?

If for some framework being used says to prune the transitive dependency, then it doesn't need to be in paket.lock for that framework, don't need to care about its dependencies, doesn't need to be downloaded. Paket might warn if such a dependency was explicitly in paket.dependencies or paket.references files for such a target framework.


I still failed to understand why Paket only puts some transitive dependencies in the .resolved file and ultimately the project (not listed in .dependencies or .references). It's only adding a few of them. Maybe those 4 bool flags give some hint? https://www.nuget.org/packages/system.buffers/

System.Buffers,4.6.1,Transitive,Main,false,true,false,true

I wanted to try find a repo on an empty project with a single dependencies+references item, but in the cases I tried it never added the System.Buffers transitive, seemingly correctly leaving it to the framework.

wnewbery avatar Nov 20 '25 10:11 wnewbery

In the case where it is necessary to manage at the paket level for multi-targets, the list is available at:

  • https://github.com/microsoft/component-detection/tree/main/src/Microsoft.ComponentDetection.Detectors/nuget/FrameworkPackages
  • https://github.com/dotnet/sdk/tree/main/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages

fpellet avatar Nov 23 '25 17:11 fpellet

Is there a list for .NET10? Neither of those repositories have .NET 10 entries, so maybe Microsoft moved the .NET 10 build stuff someplace?

Should it be the PackageOverrides.txt files under C:\Program Files\dotnet\packs once the version and frameworks is determined?

So I guess in that case paket install might want to still resolve all of these fully, but then when adding the packages into the projects (where it should be possible to determine the Sdk and TargetFramework in use?), don't include the package, and emit a Paket specific warning if the package was explicitly in paket.references that it will have no effect?

I assume .NET is only ignoring packages with a version less or equal to the framework provided one, so that if Microsoft released a package-specific fix on NuGet that can be used without updating the full SDK & runtimes?

Might be useful to try and locate exactly where the NU1510 check happens to see the conditions?

wnewbery avatar Dec 24 '25 12:12 wnewbery

  • I can confirm that DLL files are still pruned, even though NU1510 is issued.
  • Adding <NoWarn>NU1510</NoWarn> to the project file(s) (or maybe Directory.Build.props?) removes the warning, and everything works fine without any noise.
  • This warning (NU1510) will only be issued related to the PrunePackageReference feature

I suggest closing this issue, unless we are going for adding NU1510 to the list of NoWarn in Paket.Restore.targets. This could for instance be done by adding this somewhere around line 126

        <PropertyGroup Condition=" '$(RestoreEnablePackagePruning)' == 'true'">
            <NoWarn>$(NoWarn);NU1510</NoWarn>
        </PropertyGroup>

Or maybe just change line 122:

			<NoWarn>$(NoWarn);NU1603;NU1604;NU1605;NU1608;NU1510</NoWarn>

Both ways work fine with my own informal test locally, though, I have no idea whether this will remove instances of this warning that actually are useful.

aklefdal avatar Jan 07 '26 11:01 aklefdal