tech.guitarrapc.cóm

Technical updates

dotnet tool restoreでSettings file 'DotnetToolSettings.xml' was not found in the package.が出る原因と対処

dotnet toolはグローバルツールではなく、プロジェクトツールとして管理するとCIや開発メンバーの環境に依存せずツールを使うことができます。 今回は、プロジェクトのツールを復元するためdotnet tool restoreしたときに出たエラー対処についてメモです。

エラーメッセージ

プロジェクトで適当なツールを保持しているとしましょう。

$ dotnet new tool-manifest
$ dotnet tool install dotnet-test-rerun

これをCI環境で実行すると次のようなエラー起こりました。ローカルでは問題ないのにCIでだけおこる、何が何だかさっぱりわかりませんね。

$ dotnet tool restore
  Unhandled exception: Microsoft.DotNet.ToolPackage.ToolConfigurationException: Settings file 'DotnetToolSettings.xml' was not found in the package.
     at Microsoft.DotNet.ToolPackage.ToolPackageInstance.DeserializeToolConfiguration(LockFileTargetLibrary library)
     at Microsoft.DotNet.ToolPackage.ToolPackageInstance.GetToolConfiguration()
     at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
     at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
     at System.Lazy`1.CreateValue()
     at Microsoft.DotNet.ToolPackage.ToolPackageInstance.GetCommands()
     at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
     at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
     at System.Lazy`1.CreateValue()
     at Microsoft.DotNet.Tools.Tool.Restore.ToolRestoreCommand.InstallPackages(ToolManifestPackage package, Nullable`1 configFile)
     at System.Linq.Enumerable.SelectArrayIterator`2.Fill(ReadOnlySpan`1 source, Span`1 destination, Func`2 func)
     at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
     at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
     at Microsoft.DotNet.Tools.Tool.Restore.ToolRestoreCommand.Execute()
     at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult)
     at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)

GitHub Actionsのエラー例です。

image

原因

とりあえずエラーとなっているファイルがどこにあるか見てみましょう。DotnetToolSettings.xmlはツールの設定ファイルで次のパスにあります。このファイルの中身自体は問題じゃなく、ファイルパスがヒントになります。

$HOME/.nuget/packages/ツール名/ツールのバージョン/tools/ツールのターゲットフレームワーク/any/DotnetToolSettings.xml

例えばdotnet-test-rerunツールは2.1.03.0.0でそれぞれ次のようなパスになります。注目すべきはツールのターゲットフレームワークです。dotnet tool restoreが成功する条件は、実行環境にツールのターゲットフレームワークの.NET SDKが入っている必要があります。

# Windowsのパス (Linuxなら$HOMEに置き換える)
%USERPROFILE%/.nuget/packages/dotnet-test-rerun/2.1.0/tools/net8.0/any/DotnetToolSettings.xml
%USERPROFILE%/.nuget/packages/dotnet-test-rerun/3.0.0/tools/net9.0/any/DotnetToolSettings.xml

言い換えると、ツールが想定しているターゲットフレームワークに合致する.NET SDKのバージョンが入っていないと冒頭のエラーが発生します。

今回エラーが起こった私の環境は、「C#プロジェクトのターゲットフレームワークがnet8.0」「ローカルマシンには.NET 9 SDKがインストールされていた」という状況でした。

  1. ローカル環境には、.NET 9 SDKがインストールされている。CI環境はプロジェクトにあわせて.NET 8 SDKがインストールされている
  2. ローカルでツールを構成時、dotnet tool install dotnet-test-rerunで最新版3.0.0がインストールされた
  3. 同3.0.0はnet9.0だけをターゲットフレームワークとしておりnet8.0はターゲットフレームワークにない
  4. CIでdotnet tool restoreを実行するとnet8.0のパスでDotnetToolSettings.xmlを探そうとする、が見つからず冒頭のエラーが出た

仮に、3.0.0がnet8.0もターゲットフレームワークに入れていればエラーは起こらなかったし、プロジェクトのターゲットフレームワークがnet9.0をターゲットにしていてもエラーは起こりませんでした。

ちなみにGitHub Discussionではファイルアクセス権限などを指摘しているものがありますが、今回のエラーはそういった問題ではないです。なんとググっても情報がない。

dotnet tool install gherkin fails #143952 | GitHub Community

対処

原因がわかれば対処も簡単です。対処は3つ考えられます。

  1. ツールをプロジェクト合致するターゲットフレームワークをサポートしているバージョンにする
  2. ツールのターゲットフレームワークに合致する.NET SDKをインストールする
  3. 自分のプロジェクトをツールのターゲットフレームワークにあわせてしまう

1は、ツールのバージョンによって機能差がないならいいでしょう。今回は、2.1.0と3.0.0の差分はターゲットフレームワークとパッケージ更新だけだったので、2.1.0にしました。

otnet tool install dotnet-test-rerun --version 2.1.0

2は、CI環境に追加で.NET 9 SDKをインストールするだけです。そこまで悪くないですが、プロジェクトが.NET 8 SDKなので、チームメンバーの環境でも動作保証するには対応が一貫性取れてないですね。

# プロジェクトとしては8.0.xだけでいいが、ツールのために9.0.xも追加する
- uses: actions/setup-dotnet@v4
  with:
    dotnet-version: |
      8.0.x
      9.0.x

3は、ツールを動機にプロジェクトのターゲットフレームワークもあげる動きになります。バージョンの一貫性はあるものの、ほかのツールやライブラリとの整合性担保も必要になるので、普段から最新バージョン追随している環境でないと難しいケースも考えられます。1

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
  </PropertyGroup>
</Project>

まとめ

DotnetToolSettings.xmlが見つからないエラーから、ターゲットフレームワークがずれているを察するのはむりげーですね。厳しい。 WSL Ubuntuとか使っていると、Ubuntuで.NET 9 SDKを入れるのはめんどくさい2ので出会いやすいです。非Windows環境への.NET SDKのパッケージマネージャー経由の配布が微妙なんですよね。

このエラーについては、調べても情報にたどりつけないので次に出会った人が楽になることを願います。


  1. .NET9はSTSなので、.NET8のLTSよりもサポートが短いという意味でも、どちらがいいかはプロジェクトの性質によるでしょう
  2. .NET9 SDKはUbuntuならppa:dotnet/backportsの導入が必要で、公式パッケージとして得られる.NET8より各段にめんどくさい