Azure DevOps の YAML パイプラインで dotnet workload install maui が、昨日まで動いていたのに突然 40 分前後で失敗する――そんなトラブルは、YAML や .NET SDK を更新しても直らないことがあります。多くは「実行エージェント環境」「ネットワーク到達性」「キャッシュ破損」のどれか。本記事では最短で切り分け、安定化させる実務手順をまとめます。
Azure DevOps パイプラインで起きる症状:dotnet workload install maui が突然失敗する
典型的には、Azure DevOps の YAML で DotNetCoreCLI@2 のカスタムコマンドを使い、MAUI ワークロードをインストールしています。
- task: DotNetCoreCLI@2
displayName: 'Install MAUI workloads'
inputs:
command: custom
custom: workload
arguments: 'install maui'
これが数か月は問題なく動いていたのに、ある日から何も変更していないのに、約 40 分かかった後に失敗するようになります。失敗箇所は毎回同じではなく、次のような「ワークロード関連パッケージのダウンロード失敗」が例として出ます。
microsoft.maui.resizetizer.sdk(例:7.0.101)のダウンロード失敗microsoft.android.sdk.windows(例:33.0.95)のダウンロード失敗
.NET SDK を 8.0.203 → 8.0.402 のように更新しても改善しない場合、原因は「SDK の古さ」ではなく、ワークロード配布元への到達性(ネットワーク/プロキシ/サービス側)、またはキャッシュ破損、あるいは実行環境の変化にあることが多いです。
「YAMLを変えていないのに壊れる」主な理由
dotnet workload install は、MAUI を使うためのワークロード(実体はマニフェストと複数のパック)をネットワーク越しに取得します。つまり、パイプライン定義が同じでも、外部要因で結果が変わり得ます。
| 変わるもの(YAML無変更でも起きる) | 現場でよくある変化 | 失敗につながるポイント |
|---|---|---|
| Microsoft-hosted エージェントの VM イメージ | windows-latest などのラベルは、中身の更新が継続的に入る | プリインストールされる SDK/ツール/証明書ストア/ネットワーク設定が変わる |
| ワークロードのマニフェスト/パック配布状況 | CDN 側の一時的な不調、ミラーの切替、帯域制限 | 「特定パッケージだけ落ちる」「時間帯で成功率が変わる」など |
| 社内ネットワーク(Self-hosted の場合) | プロキシの変更、TLS/中間証明書更新、回線品質の劣化 | 巨大パッケージの途中切断や、SSL 検査での失敗が増える |
| キャッシュの整合性(Self-hosted で顕著) | 途中まで落ちたファイルが残る、ディスク不足、ウイルス対策のロック | 以降の実行でも同じ場所で失敗し続けることがある |
| 利用される .NET SDK の選択 | global.json により意図せず古い SDK が選ばれる | 「SDK を更新したつもり」が、実際は更新されていない |
最初に確認する:Microsoft-hosted か Self-hosted か
切り分けの最短ルートは、まずどこで実行されているかを確定させることです。原因の当たりどころが大きく変わります。
| 項目 | Microsoft-hosted エージェント | Self-hosted エージェント |
|---|---|---|
| 実行環境 | ジョブごとに新しい VM。実行後は破棄される | 同じマシン/VM に継続してジョブが乗る |
| 失敗の典型 | 外部サービスやネットワーク経路の揺らぎ、VM イメージ更新の影響 | プロキシ/ファイアウォール/証明書/回線、ディスク、キャッシュ破損 |
| 再現性 | 時間帯・リージョン・混雑で変動しやすい | 環境が固定されるぶん、原因を潰せば安定しやすい |
| 対処方針 | ログで URL/失敗点を特定し、固定化(イメージ/SDK/ワークロード)とリトライ設計 | ネットワーク設定の見直し、キャッシュのクリア/修復、端末の健全性確保 |
まずは「実行環境」と「実際に使われている SDK」をログに出す
「更新したのに直らない」を潰すため、インストール直前に次を出力しておくと後が楽です。
- powershell: |
dotnet --info
dotnet --list-sdks
dotnet --version
dotnet workload --info
displayName: 'Dump .NET info'
global.json があるリポジトリでは、パイプライン上に新しい SDK を入れても、コマンド実行時に古い SDK が選ばれることがあります。まず「実際に何が動いているか」を確定させてください。
原因を見える化する:--verbosity detailed で落ちる箇所を特定
ワークロードインストールの失敗は、表面上は「Downloading xxx failed」だけでも、裏でどのフィード/URL から取ろうとして、どのタイミングで失敗したかが分かると原因が一気に絞れます。まずは詳細ログを有効化します。
- task: DotNetCoreCLI@2
displayName: 'Install MAUI workloads (detailed)'
inputs:
command: custom
custom: workload
arguments: 'install maui --verbosity detailed'
さらに踏み込む場合は --verbosity diagnostic にします。CI のログが増えるので、最初は detailed で十分です。
ダウンロード失敗の定番原因と、現場で効く対処
ネットワーク経路の揺らぎ(CDN/プロキシ/SSL検査)
MAUI 関連のパックはサイズが大きく、ダウンロード途中で切れると 30〜40 分といった長い時間を使った後に失敗しがちです。特に Self-hosted で企業ネットワーク配下の場合、次の要因が直撃します。
- プロキシ設定が必要なのに未設定(または最近変更された)
- SSL インスペクションで証明書チェーンが変わり、信頼できない状態になった
- 外向き通信の帯域制限/アイドルタイムアウトが厳しい
- 一部の配布先ドメインだけ許可されておらず、パックの取得に失敗する
対処としては、まず詳細ログに出てくる取得先を見て、ネットワークチームが追える形(どのドメイン/ポートが必要か)に落とし込みます。Self-hosted なら、同じマシンで PowerShell から手動で dotnet workload install maui を実行し、同じ失敗が再現するかも重要な判断材料です。
途中まで落ちたパックによる「キャッシュ破損」
ネットワークが一瞬でも落ちると、ダウンロード途中のファイルが残り、以降の実行で何度も同じ場所で失敗することがあります。Self-hosted で「昨日まで OK、今日からずっと NG」になったときは、まずこれを疑います。
定番の手当は次の順番が安全です(影響範囲が小さいものから)。
- NuGet のローカルキャッシュをクリアする
- workload の repair を実行する
- 必要なら uninstall → clean → install をやり直す
# 1) NuGet キャッシュのクリア
dotnet nuget locals all --clear
# 2) インストール済みワークロードの修復
dotnet workload repair
# 3) それでもダメなら(影響大なので専用エージェント推奨)
dotnet workload uninstall maui
dotnet workload clean --all
dotnet workload install maui --verbosity detailed
注意:dotnet workload clean --all は「全 SDK 版数」にまたがってコンポーネントを削除します。Self-hosted で複数プロジェクトが同居している場合は、ビルド専用マシン/専用エージェントで実施するのが安全です。
NuGet ソースの問題(認証・優先順位・ミラー)
企業環境では、nuget.config に社内フィードが追加されていたり、外部(nuget.org)がミラー経由になっていたりします。ここで認証が切れる/優先順位が変わると、ワークロード取得が不安定になります。
切り分けポイントは次のとおりです。
| 観察できる症状 | まず疑うこと | 優先する対処 |
|---|---|---|
| 社内だけ失敗し、個人回線では成功する | プロキシ/SSL 検査/外向き許可 | ネットワーク設定の見直し、必要ドメインの許可 |
| 特定フィードが落ちた時だけ失敗する | 単一ソース依存、フェイルオーバー不足 | --ignore-failed-sources や複数 --source の検討 |
| 認証が必要なフィードを参照している | CI で対話認証できない | Azure DevOps の認証タスク/サービス接続の見直し |
とくに --ignore-failed-sources は「一部ソースの障害を警告扱いにする」オプションです。複数ソースがあり、代替ソースが有効なケースで効きます。単一ソースしかない場合は根本解決になりません。
Microsoft-hosted エージェントの「実行環境が変わった」問題
Microsoft-hosted ではメンテナンスと更新が自動で行われます。windows-latest のようなラベルを使っていると、VM イメージ更新により、ある日突然ツール構成が変わることがあります。
再現性を上げるための実務的な対処は次の 2 つです。
- VM イメージを固定する:
windows-latestではなくwindows-2022など明示的なイメージに固定する - .NET SDK を固定する:
UseDotNet@2で SDK バージョンを指定し、ログでdotnet --versionを確認する
pool:
vmImage: 'windows-2022'
steps:
* task: UseDotNet@2
displayName: 'Install .NET SDK'
inputs:
packageType: 'sdk'
version: '8.0.402'
「SDK を更新したのに直らない」ケースでも、実際は別の SDK が選択されていることがあります。必ず dotnet --version を出して確認してください。
workload-set と manifests の違いを理解して「ワークロードを固定化」する
.NET 8.0.400 以降、ワークロードはworkload-set(ワークロード一式にバージョンを付ける考え方)で固定できるようになりました。CI では「毎回最新に追随」よりも、「同じものを再現できる」方がトラブルが減ります。
dotnet workload --version:現在のワークロードセット版数を表示dotnet workload config --update-mode workload-set:workload-set モードに切替global.jsonのworkloadVersion:リポジトリとして固定(チームで揃える)
{
"sdk": {
"version": "8.0.402",
"workloadVersion": "8.0.402"
}
}
この固定化は「ダウンロード失敗を直接直す」ものではありませんが、毎回違うワークロードを引いてしまう状況を避け、調査と再現性を大幅に改善します。
再発防止:MAUI ビルドを安定させるパイプライン設計
ワークロードのインストールはネットワーク依存が強いので、「失敗しにくい構成」に寄せるのが最終的に一番早いです。現場でよく採用される打ち手を、安定度と運用コストで整理します。
| 方針 | 安定度 | 速度 | 運用コスト | 向いているチーム |
|---|---|---|---|---|
毎回 Microsoft-hosted で workload install | △ | △(毎回DL) | 低 | まず動けば良い/小規模 |
| Microsoft-hosted + パッケージ/ワークロードのキャッシュ | ○ | ○ | 中 | 実行回数が多い/ビルド時間を縮めたい |
| Self-hosted にワークロードを事前導入(固定) | ◎ | ◎ | 中〜高 | 安定最優先/社内ネットワーク前提 |
| カスタムイメージ(VM/スケールセット)で標準化 | ◎ | ◎ | 高 | 複数プロジェクト/長期運用 |
キャッシュを使って「毎回の巨大ダウンロード」を減らす
Microsoft-hosted はジョブごとに VM が破棄されるため、何もしないと毎回ゼロからダウンロードになります。NuGet パッケージのキャッシュはパイプラインキャッシュで大きく改善できます。
例として、NuGet のグローバルパッケージフォルダを固定してキャッシュします。
variables:
NUGET_PACKAGES: '$(Pipeline.Workspace)/.nuget/packages'
steps:
* task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | **/packages.lock.json'
restoreKeys: |
nuget | "$(Agent.OS)"
path: '$(NUGET_PACKAGES)'
キャッシュキーに packages.lock.json を使う場合は、ロックファイルを生成する運用(依存関係の固定)もセットで考えると、再現性と速度が両立しやすくなります。
ワークロードのパック自体もキャッシュ対象にしたくなりますが、サイズが大きくなりがちです。まずは NuGet 側のキャッシュを整え、効果と容量のバランスを見て拡張していくのが現実的です。
リトライを「コマンド側」で持つ(外部要因に強くする)
外部配布元の一時不調やネットワーク瞬断が原因なら、同じ手順でも「次は通る」ことがあります。CI で毎回手動リランに頼らず、失敗したら数回だけ再試行するのは実務で効きます。
- powershell: |
$ErrorActionPreference = "Stop"
$max = 3
for ($i = 1; $i -le $max; $i++) {
try {
dotnet workload install maui --verbosity detailed
break
} catch {
if ($i -eq $max) { throw }
Start-Sleep -Seconds (20 * $i)
}
}
displayName: 'Install MAUI workloads with retry'
ポイントは「無限リトライ」にしないことと、「リトライの前にキャッシュを疑う(必要ならクリア)」を組み合わせることです。
フォーラム上の結論:Microsoft Q&A では Azure DevOps パイプラインはサポート対象外
今回の事象と同様の相談が Microsoft Q&A に投稿されたケースでは、受理された回答としてAzure DevOps(パイプライン)のトラブルは Q&A のサポート対象外であり、Developer Community(開発者コミュニティ)で相談するよう案内されています。つまり、そのスレッド内では技術的な解決策が提示されませんでした。
その一方で、実務としては次の 3 点を押さえるだけで、原因の当たりが付くことが多いです。
- Microsoft-hosted / Self-hosted を切り分ける(環境要因かどうか)
--verbosity detailedで、どの URL/どのタイミングで落ちているかを特定する- サービス側の障害や不調がないか、Azure DevOps のステータス(インシデント)を確認する
Developer Community に相談する場合も、上記の情報が揃っているほど、回答が早く・正確になります。
まとめ:最短で直すチェックリスト
- 実行エージェント種別(Microsoft-hosted / Self-hosted)を確認する
dotnet --versionとdotnet workload --infoをログに出し、「実際に使われている SDK」を確定するdotnet workload install maui --verbosity detailedで、落ちている取得先とタイミングを特定する- Self-hosted なら
dotnet nuget locals all --clear→dotnet workload repairを試す - Microsoft-hosted なら VM イメージと SDK を固定し、必要ならキャッシュ/リトライを入れる
- 長期運用では、Self-hosted やカスタムイメージでワークロードを事前導入し、ネットワーク依存を最小化する
「YAML も SDK も変えていないのに突然壊れた」問題ほど、ログの粒度と切り分け順で解決までの時間が変わります。まずは詳細ログ化とエージェント種別の確定から始めてください。

コメント