Azure DevOps の「TF401398: The pull request cannot be activated because the source and/or the target branch no longer exists, or the requested refs are not branches」
「ソースかターゲットのブランチがもう無いか、指定された ref がブランチではないので、プルリクエストを有効にできない」という意味です。新しいプルリクエストのソースかターゲットを、サーバーのブランチとして受け取れないときに返ります。この文は2つの違う間違いをまとめていて、どちらのブランチのことかも言いません。ブランチが無い(push していない・push が断られた・消された)か、名前がブランチの参照の形でない(REST API が refs/heads/develop を待っているのに develop を送った、など)かです。
答えの全体
HTTP/1.1 400 Bad Request
{"$id":"1","innerException":null,"message":"TF401398: The pull request cannot be activated because the source and/or the target branch no longer exists, or the requested refs are not branches","typeName":"Microsoft.TeamFoundation.Git.Server.GitPullRequestCannotBeActivated, Microsoft.TeamFoundation.Git.Server","typeKey":"GitPullRequestCannotBeActivated",…}
- 2018年〜2026年10月の公開の報告は、REST API、プルリクエストを作るパイプラインのタスク、Azure DevOps の上の Dependabot と Renovate、プルリクエストを開くコーディング エージェントからこの文を引いています。
- 「ソースかターゲット」のどちらかを、サーバーは言いません。2026年9月の、そうしたエージェントについての報告もまさにそう書いていて、そのコードは直前にソースを push したことを頼りに、TF401398 をすべて「ターゲットが無い」として扱っています。
どちらのブランチかを見分ける
- git で:
git ls-remote --heads origin <ソース> <ターゲット>は、サーバーにあるものだけを出します。何も出ない名前がそれです。 - REST API で:
GET …/_apis/git/repositories/<リポジトリ>/refs?filter=heads/<ブランチ>。filter は名前の先頭で合わせるので、heads/mainはmain-oldも返します。valueの中にちょうどrefs/heads/<ブランチ>があるかを見ます。 - Web で:Repos → Branches で、2つの名前を探します。
公開の報告が挙げる原因
- 名前が
refs/heads/の形でない。REST API はsourceRefNameとtargetRefNameをrefs/heads/developのような完全な参照で受け取ります。2024年5月の Scala Steward の報告は、ターゲットをdevelopで送って TF401398 になっていました。接頭辞が2回でも同じです。2020年のパイプラインのタスクの報告では、$(Build.SourceBranch)がもうrefs/heads/…を持っているのに、もう一度付けてrefs/heads/refs/heads/…を送っていました。2024年9月の Dependabot の報告では、refs/heads/masterがブランチ名の中に入っていました。 - ソース ブランチがサーバーに届いていない。push していないか push が断られて、プルリクエストにソースが無い場合です。2021年の Dependabot の報告2件では、パイプラインを動かすビルド サービスの ID に許可が足りませんでした。どちらもプロジェクトにビルド サービスの ID が2つあり、1件は Contribute to pull requests の許可を挙げています。正しい ID に許可を付けると、プルリクエストが作れました。断られた push は、push の出力に理由が出ます。保護されたブランチなら TF402455 を見てください。
- フォルダーと同じ名前のブランチがある。git は
dependabotというブランチとdependabot/nuget/…というブランチを同時に持てないので、後の方の push が失敗します。2021年の Dependabot の報告は、dependabotというブランチを消して TF401398 を直していました。 - 確かめた後でブランチが消された。たとえばターゲットをほかの人が消した、ソースを前のプルリクエストの完了がブランチごと消した、などです。
どうするか
- 上のやり方で、2つの名前を探します。
- ソースが無いなら、push して(
git push -u origin <ブランチ>)、push の出力を読みます。断られた push ではブランチはできません。 - ターゲットが無いなら、Repos → Branches に並んでいるブランチをターゲットにします。リポジトリの既定のブランチにはそこで印が付いています。
- どちらも並んでいるなら、名前の送り方を見ます。スクリプトや REST の呼び出しでは、
refs/heads/<名前>をちょうど1回付けて送ります。
IntelliJ IDEA と Rider で Azure DevOps のプルリクエストを
Azure DevOps Pull Requests は、Lesstep が作っている JetBrains IDE(2024.1 以降)と Android Studio のプラグインです。組織・プロジェクト・リポジトリを git のリモートから読み、自分のレビューを待っているプルリクエストを IDE のツールウィンドウに並べます。Azure DevOps Services でも Azure DevOps Server でも使えます。Azure DevOps のプルリクエストを作成は、まずいまのブランチがサーバーにあるかを確かめ、無ければ IDE の push の画面を開きます。ターゲットは、サーバーにあるブランチから選びます。1.0.37 からは、それでも TF401398 が返ったとき、2つのブランチを調べて、無い方を名指しします。レビューの受け箱は無料、投票・コメント・完了・作成は Pro(30日間の無料試用つき)です。画面は日本語です。
Azure DevOps は Microsoft Corporation の商標、IntelliJ IDEA と Rider は JetBrains s.r.o. の商標です。このページは Microsoft・JetBrains のいずれとも提携しておらず、承認も受けていません。
ほかに:TF401179:アクティブなプルリクエストがもうある · TF402455:このブランチへの push は許可されていない · TF401175:その名前のブランチが無い · English