2025年9月ごろから、Azure DevOps などの Hosted Agent で Azure CLI が自動的に 2.77 に上がった環境で、これまで問題なく動いていた az batch application package create が突然失敗し、パイプライン全体が停止するケースが相次ぎました。本記事では、この現象の正体(Azure CLI 2.77 固有のリグレッション)と、いますぐ取れる回避策・恒久対処・将来同じトラブルを避ける設計のポイントを、具体的な YAML 例やコマンド付きで詳しく解説します。
Azure CLI 2.77 で何が起きたのか
Azure Batch にアプリケーション パッケージを登録するために、多くの現場では次のようなコマンドをパイプラインで自動実行しています。
az batch application package create \
--application-name <appName> \
--name <batchAccountName> \
--package-file /path/to/app.zip \
--resource-group <resourceGroup> \
--version-name <version>
ところが Azure CLI が 2.77.0 になると、これまで正常に動作していた同じコマンドが、以下のいずれかのパターンで失敗・異常動作するようになりました。Azure CLI の GitHub Issue(#32086)や Microsoft Q&A でも同様の事象が報告されています。
- 既存バージョンに上書きしようとすると失敗し、
ERROR: The specified blob already existsが発生する - 新しい
--version-nameを指定しても、アップロードされた BLOB の中身が ZIP の実体ではなく、ZIP ファイルのパス文字列になってしまう
特に 2 つ目の「ZIP の中身がファイル パス文字列になる」症状は致命的で、ジョブ実行時にアプリケーションが展開できず、Batch プール全体がエラーになってしまいます。Microsoft Q&A の報告でも、Hosted Agent で 2.77 になった直後から同じ現象が再現していることが確認できます。
発生条件と典型的なエラー メッセージ
報告事例と再現テストを整理すると、以下の条件がそろったときに問題が顕在化します。
- Azure CLI のバージョンが 2.77.0
az batch application package createコマンドを使用- Azure Batch アカウントの Auto Storage を利用(一般的な構成)
- Azure DevOps / GitHub Actions などの Hosted Agent、もしくは手元の環境で 2.77.0 を利用
典型的なエラー メッセージは次のとおりです。
ERROR: The specified blob already exists.
RequestId:xxxxxxx
Time:2025-09-09T08:06:02.3395538Z
ErrorCode:BlobAlreadyExists
このエラーを避けるため、--version-name にユニークな値を付けて BLOB の重複を避けると、こんどはアップロードされた BLOB の中身が
D:\a\1\drop\MojitoUpload.zip
のようなファイル パスの文字列だけになってしまう、という二重の不具合が確認されています。
発生パターンの整理
| CLI バージョン | 操作内容 | 結果 |
|---|---|---|
| 2.76.x | 既存の --version-name に再アップロード | BLOB 上書きに成功(従来挙動) |
| 2.77.0 | 既存の --version-name に再アップロード | BlobAlreadyExists エラーで失敗 |
| 2.77.0 | 新しい --version-name を指定 | BLOB の中身が ZIP 実体ではなく ZIP ファイルのパス文字列だけになる |
| 2.78.0 以降 | 新規/上書きアップロード | どちらも正常にアップロードされる |
原因: Azure CLI 2.77 のリグレッション
この現象は、Azure CLI 2.77.0 における リグレッション(後退バグ) として、Azure CLI チームに報告されています。
- 2.76 以前: 既存バージョンがあっても BLOB の上書きが行える動作
- 2.77.0: 内部のアップロード処理が変更され、既存 BLOB の扱いとアップロード データの渡し方に問題が入り込んだ
- 結果として
- 既存 BLOB に対しては
BlobAlreadyExistsが返る - 新しい BLOB であっても、アップロードされる内容がファイル パス文字列になってしまう
- 既存 BLOB に対しては
つまり、ユーザー側のスクリプトや ZIP の作り方が悪いわけではなく、Azure CLI 2.77 自体の不具合です。そのため、いくら YAML や PowerShell を見直しても根本的な解決にはつながりません。
恒久対処: Azure CLI 2.78 以降にアップグレード
Azure CLI 2.78.0 のリリース ノートには、Batch セクションで
Fix #32086, #32090: az batch application package create: Fix blob not being uploaded
と明記されており、この問題が 2.78.0 で修正されたことが公式にアナウンスされています。
2.78.0 は 2025 年 10 月 14 日付けでリリースされており、このバージョン以降であれば az batch application package create によるアップロードは再び正常に動作します。
ローカル環境でのアップグレード例
ローカル PC に Azure CLI をインストールしている場合は、通常のアップデート手順で 2.78 以上に更新すれば問題は解消します。
- Windows(MSI インストーラー版): 公式インストーラーで上書きインストール
- Windows / Linux(
pipで入れている場合):pip install --upgrade "azure-cli>=2.78.0" az --version # バージョン確認 - コンテナーを利用している場合:
docker pull mcr.microsoft.com/azure-cli:2.78.0
Azure DevOps Hosted Agent でのアップグレード戦略
Hosted Agent では、イメージにあらかじめインストールされている Azure CLI のバージョンは自動更新されるため、「気付いたら 2.77 になっていた」という状況が起こり得ます。ここで重要なのは、パイプラインの中で明示的に CLI バージョンを固定することです。
一例として、ジョブの冒頭で 2.78 以上をインストールし直す方法があります。
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.10'
- script: |
pip install --quiet "azure-cli>=2.78.0"
az --version
displayName: 'Ensure Azure CLI >= 2.78'
- script: |
az batch application package create \
--application-name $(appName) \
--name $(batchName) \
--package-file $(Pipeline.Workspace)/drop/$(projectName).zip \
--resource-group $(resourceGroup) \
--version-name $(Build.BuildNumber)
displayName: 'Upload Batch Application Package'
このようにジョブ内で Azure CLI を「上書きインストール」することで、Hosted Agent 側の事前インストール バージョンに依存しない、安全なパイプラインを構築できます。
今すぐ運用を復旧するための一時回避策
すぐに CLI 2.78 以上が使えない場合、以下のような一時回避策が考えられます。それぞれのメリット・デメリットを理解したうえで選択してください。
| 回避策 | 概要 | ポイント |
|---|---|---|
| ① CLI を 2.76 にダウングレード | パイプライン内で 2.76 を明示的にインストールし、問題のないバージョンに固定する | 最もシンプルで再現性が高い。CLI 2.77 を事実上スキップする運用 |
| ② REST API / SDK でアップロード | Azure Batch 管理 REST API や SDK を使ってアプリケーション パッケージを登録する | CLI のバグに依存しない。本番向けの堅牢なアプローチ |
| ③ バージョン名を毎回ユニークにする | --version-name にビルド番号や日時を含めて Blob 重複を避ける | 2.77 では「パス文字列がアップロードされる」問題が残るため、2.77 そのものの回避にはならない |
| ④ CLI バージョン & ZIP 内容チェック | パイプライン内で CLI バージョンと ZIP の中身を検証し、異常時に早期に失敗させる | 将来同種のリグレッションが起きたときにも検知しやすくなる |
回避策①: Azure CLI を 2.76 にダウングレード
もっとも現実的で導入しやすいのが「問題のない 2.76 に戻す」方法です。Hosted Agent でも、パイプライン内で pip を使って CLI を上書きインストールできます。
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.10'
- script: |
pip install --quiet "azure-cli==2.76.*"
az --version
displayName: 'Install Azure CLI 2.76'
- script: |
az batch application package create \
--application-name $(appName) \
--name $(batchName) \
--package-file $(Pipeline.Workspace)/drop/$(projectName).zip \
--resource-group $(resourceGroup) \
--version-name $(Build.BuildNumber)
displayName: 'Upload Batch Application Package'
ポイントは次の通りです。
- 毎ジョブ実行時に 2.76 をインストールすることで、Agent イメージ側のバージョン変更に影響されなくなる
- ビルド時間がわずかに延びるものの、Batch ジョブ全体の安定稼働と比べれば小さいコスト
- CLI 2.78 以降が十分に展開されたタイミングで、このダウングレード処理を削除すればよい
回避策②: REST API / SDK でアプリケーション パッケージを登録
Azure CLI を使わず、Azure Batch 管理 REST API や SDK で直接パッケージを登録する方法もあります。REST API の Application Package – Create / Activate エンドポイントや、Python SDK の BatchManagementClient.application_package などを利用できます。
フローは概ね次の通りです。
- 管理プレーン API で「アプリケーション パッケージ レコード」を作成する
- このとき、アップロード先を示す
storageUrl(SAS 付き URL)が返される
- このとき、アップロード先を示す
- 返された
storageUrlに対して、通常の BLOB アップロード(PUT)で ZIP ファイルを送信する - アップロード完了後、パッケージを Activate する API を呼び出して有効化する
Python で行う簡易例(概略)は次のようになります。
from azure.identity import DefaultAzureCredential
from azure.mgmt.batch import BatchManagementClient
from azure.storage.blob import BlobClient
import requests
subscription_id = "<your-subscription-id>"
resource_group = "<rg-name>"
account_name = "<batch-account-name>"
app_name = "<application-name>"
version_name = "<version>"
zip_path = "app.zip"
cred = DefaultAzureCredential()
client = BatchManagementClient(cred, subscription_id)
# 1. パッケージ レコードを作成
pkg = client.application_package.create(
resource_group_name=resource_group,
account_name=account_name,
application_name=app_name,
version_name=version_name,
)
storage_url = pkg.storage_url # SAS URL
# 2. storageUrl に ZIP をアップロード
with open(zip_path, "rb") as f:
requests.put(storage_url, data=f)
# 3. パッケージを Activate
client.application_package.activate(
resource_group_name=resource_group,
account_name=account_name,
application_name=app_name,
version_name=version_name,
parameters={"format": "zip"},
)
この方法であれば Azure CLI のバグに依存しないため、将来的に CLI の実装が変わっても影響を受けにくく、本番環境向けとしても有力な選択肢になります。
回避策③: バージョン名を毎回ユニークにする(注意点あり)
BlobAlreadyExists エラー自体は、「同じ Blob 名に再アップロードしようとした」ことが原因です。そのため、--version-name を毎回ユニークにすれば、少なくともこのエラーは回避できます。
--version-name $(Build.BuildNumber)--version-name $(Date:yyyyMMdd-HHmmss)--version-name $(Build.SourceBranchName)-$(Build.BuildId)
しかし、Azure CLI 2.77 の場合は、「新しいバージョンを作っても BLOB の中身がパス文字列になってしまう」バグが残っているため、2.77 を使い続ける限り、ユニークなバージョン名だけでは根本解決になりません。
したがって、この回避策は「2.76 や 2.78 以降で運用しているが、うっかり同じバージョン名を再利用してしまう」ケースを避けるためのベスト プラクティスとして捉えるのがよいでしょう。
回避策④: パイプラインで CLI バージョンと ZIP 内容を検証
将来また似たようなリグレッションが発生した場合に備え、「CLI バージョン」と「アップロード対象の ZIP の正当性」をパイプラインで常に検証しておくと安心です。
例えば Azure DevOps の Linux Hosted Agent であれば、次のような追加ステップを入れることができます。
- script: |
echo "Azure CLI version:"
az --version | head -n 5
echo "Check package file:"
ls -l "$(Pipeline.Workspace)/drop/$(projectName).zip"
unzip -t "$(Pipeline.Workspace)/drop/$(projectName).zip"
displayName: 'Sanity check CLI & ZIP'
これにより、
- CLI が意図しないバージョン(例: 2.77)のままになっていないか
- ZIP が 0 バイトや明らかに小さすぎるサイズではないか
- 解凍テストが通るか
といったチェックを自動化でき、異常があれば az batch application package create を実行する前にパイプラインを失敗させることができます。
Azure DevOps / GitHub Actions でのバージョン固定パターン
Hosted Agent 環境では、OS やイメージ タグごとに Azure CLI の更新タイミングが異なります。そこで、プラットフォームごとに「CLI バージョンをどう固定するか」を整理しておきます。
| 環境 | バージョン固定の例 | ポイント |
|---|---|---|
| Azure DevOps (Ubuntu) | pip install "azure-cli==2.76.*" または pip install "azure-cli>=2.78.0" | UsePythonVersion タスクで Python を用意してから実行 |
| Azure DevOps (Windows) | Powershell スクリプトで pip install azure-cli を実行 | pip 用 Python は UsePythonVersion などで事前にインストール |
| GitHub Actions | actions/setup-python で Python を入れた後、pip install azure-cli | runs-on: ubuntu-latest など Hosted Runner でも同様に制御可能 |
| コンテナー ベース | mcr.microsoft.com/azure-cli:2.76.0 や :2.78.0 を明示 | Docker イメージ自体にバージョンを固定するため最も再現性が高い |
Batch アプリケーション パッケージ運用のベスト プラクティス
今回のようなリグレッションへの対応に加えて、Azure Batch のアプリケーション パッケージを安定運用するうえで、以下のような設計をしておくと安心です。
バージョン命名規則を決めておく
appname-YYYYMMDD-HHmmssappname-$(Build.BuildNumber)appname-$(Build.SourceBranchName)-$(Build.BuildId)
など、ビルド番号や日時を含めたルールを決めておくことで、意図しない上書きや混乱を防げます。CLI 2.77 のような特殊なバグがなければ、これだけでも相当な安定性向上につながります。
アプリケーションごとに「安定版」バージョンを決める
ジョブから参照するバージョンを
- 常に最新(例: CI ビルドごとに更新)
- リリースごとに固定(例:
1.0.0,1.1.0)
のどちらに寄せるかを設計し、「どのタイミングで既存バージョンを上書きするか」を決めておくと、今回のような「上書きできなくなって慌てる」状況を減らせます。
管理プレーンとデータプレーンを分離して考える
Azure Batch のアプリケーション パッケージは、「管理プレーン API(パッケージ レコード作成/有効化)」と「ストレージへの BLOB アップロード(データプレーン)」の組み合わせで成り立っています。
- Azure CLI はこの 2 つをまとめてラップしている
- REST API / SDK を利用すると、両者を明示的に制御できる
という構造を意識しておくと、CLI に問題が出たときも「最悪 REST / SDK に逃げる」という選択肢をすぐに取れるようになります。
トラブル発生時のチェックリスト
もし今まさに az batch application package create でエラーが出ている場合は、以下のチェックリストに沿って原因を切り分けてみてください。
- CLI バージョンの確認
az --versionを実行し、2.77.0 でないか確認する- 2.77.0 であれば、本記事の説明してきたリグレッションに該当する可能性が高い
- パッケージ ZIP の確認
- ビルド成果物のパスが正しいか(スペース・日本語パスなど)
- サイズが期待通りか / 解凍テストが通るか
- Batch アカウントとアプリケーション設定
- 対象のアプリケーション名・バージョンが正しく指定されているか
- Auto Storage アカウントが有効か
- CLI バージョン固定の有無
- パイプライン内で明示的に CLI をインストールしているか
- Hosted Agent のイメージ更新に左右されていないか
まとめ
- Azure CLI 2.77.0 には、
az batch application package createコマンドに関するリグレッションが存在し、BlobAlreadyExistsエラーや ZIP の中身がパス文字列になる問題が発生します。 - Azure CLI 2.78.0 以降でこのバグは公式に修正されているため、可能であれば 2.78 以上へのアップグレードが最も確実な恒久対策です。
- 今すぐの復旧には、CLI を 2.76 にダウングレードする、あるいは REST API / SDK でアプリケーション パッケージを登録するといった回避策が有効です。
- Hosted Agent 環境では、パイプライン内で Azure CLI のバージョンを明示的にインストールし、イメージ更新に影響されない構成にしておくことが重要です。
- バージョン命名規則の整理、管理プレーンとデータプレーンの分離設計、ZIP 内容の検証ステップなどを取り入れることで、今後同様のリグレッションが起きた場合でも影響を最小限にできます。
すでに影響を受けている環境では、まず CLI 2.77.0 が使われていないか を確認し、ダウングレードまたはアップグレードによって安全なバージョンに切り替えたうえで、暫定対処を徐々に外していくのがおすすめです。

コメント