Claude Media
claude-code-actionのInvalid branch nameエラーの原因と対処法

claude-code-actionのInvalid branch nameエラーの原因と対処法

claude-code-actionがPRの既存ブランチ名を「Invalid branch name」で拒否する原因と、#や括弧など許可文字が増えてきた修正の経緯、現在の対処法をまとめます。

claude-code-actionの「Invalid branch name」エラーとは

「Invalid branch name」は、anthropics/claude-code-actionがPRやIssueの処理を始める直前に対象ブランチ名を検証し、独自の許可文字リストに合わない既存ブランチを弾いて処理を止めるエラーです。エラーメッセージは次の形で出ます。

Error: Prepare step failed with error: Invalid branch name: "feature/#12345-some-name". Branch names must start with an alphanumeric character and contain only alphanumeric characters, forward slashes, hyphens, underscores, or periods.
Error: Process completed with exit code 1.

この文言は検証が入った当初のものです。現在のmainでは、どのルールに当たったかによって文末が変わります。たとえば#を含む名前は今は通り、空白を含む名前なら「cannot contain control characters, spaces, or special git characters」で止まります。文言ごとの違いは後半の表にまとめています。

対象になるのは、これから作る新しいブランチ名ではなく、すでにリポジトリに存在するPRのheadブランチやbaseブランチです。issueで最初に報告された例は#8982-bugfixで、以後feature/#12345-some-name(GitHubのIssue番号を先頭に含む命名規則)やfix(scope)/the-branch-name(Conventional Commits風のスコープ表記)など、Gitとしては正当なのに拒否される命名パターンが複数報告されています(issue #751)。put-back-arm64-#2のような名前も、別のissue(#1137)で報告され、PR #1167で修正されました。

issueのコメント欄には実運用での影響も具体的に書き込まれています。ある投稿者は、Issue番号をブランチ名に含める社内規則があるためGitHub Actions上のPRレビューが軒並み失敗すると報告し、別の投稿者は最終的にclaude-code-actionの利用をやめてCopilotなど他のPRレビューbotへ乗り換えたとコメントしました。Gas Townというツールの利用者が、ツール側のブランチ名テンプレートを変えて回避した例もありました。

検証はsetupBranch()という関数の中で3つの経路に対して呼ばれます。PRイベントで動くときはheadブランチ(branchName)を検証してからチェックアウトし、PRがopenであればマージ先のbaseブランチ(prData.baseRefName)も追加で検証します。Issueイベントで新規ブランチを作るときは、分岐元になるソースブランチと、これから作る新しいブランチの両方が対象です。Claude Codeが自分で生成するブランチ名はbranch_name_template(既定値{{prefix}}{{entityType}}-{{entityNumber}}-{{timestamp}})とbranch_prefix(既定値claude/)から作られます。既定のままならclaude/issue-123-20260101-1200のような形になり、検証を通ります。

生成した名前も同じ検証にかかります。当たりやすいのは、ユーザー側がすでに作っていた既存ブランチをPRトリガーで読み込む場面と、branch_prefixやテンプレートを書き換えた場面です。フォークからのPRも例外ではなく、headブランチ名を検証してからpull/<番号>/headを取得します。

エラーの原因 — コマンドインジェクション対策のホワイトリスト

この検証はPR #736で導入されました。それ以前はBunの$シェルテンプレートリテラルでgitコマンドを組み立てており、ブランチ名をそのままシェルに渡す構造だったため、悪意のあるブランチ名によるコマンドインジェクションの余地がありました。PR #736はgit呼び出しをexecFileSync(シェルを経由せず引数を直接プロセスに渡す方式)に置き換え、あわせてvalidateBranchName()という関数でブランチ名を正規表現のホワイトリストと照合するようにしました。

導入時点の正規表現は次のとおりです。

const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/;

英数字・スラッシュ・ハイフン・アンダースコア・ピリオド以外を全て拒否する厳格な作りで、#や+、,、@、()のようにGit自身は許可している文字(git-check-ref-formatで定義)まで一律に弾いていました。execFileSyncはシェルを経由しないため、これらの文字が混ざっていてもコマンドインジェクションのリスクは生じません。結果として、導入時のホワイトリストは安全性を保ったまま後から緩められる作りでした。

このPRにはもう1つ、先頭のダッシュ(-)を拒否する独立したチェックも含まれていました。git checkout --helpのように、ブランチ名の先頭が-だとgitコマンドのオプションとして誤解釈されてしまう「CLIオプションインジェクション」は、シェルを経由しないexecFileSync化そのものでは防げない別種のリスクです。この先頭ダッシュ禁止だけは、後続のどの緩和PRでも一貫して手を付けられていません。

#・+・,・@・括弧が使えるようになった経緯

issue #751は2025年12月17日に登録されましたが、実際の修正は文字ごとに個別のPRへ分かれて進みました。src/github/operations/branch.tsのコミット履歴を見ると、次の順で許可文字が広がっています。

あゆみ

許可文字が増えた順序(branch.tsのコミット履歴)

  1. 2026-04-05PR #1167で「#」

    きっかけはissue #1137です。

  2. 2026-04-23PR #1248で「+」

    きっかけはissue #1244です。

  3. 2026-05-14PR #1310で「,」

    きっかけはissue #1300です。

  4. 2026-06-22PR #1411で「@」(先頭位置を含む)

    きっかけはissue #998です。

  5. 2026-07-16PR #1486で先頭の「_」

    きっかけのissueは付いていません。

  6. 2026-08-25PR #1710で括弧「()」

    きっかけはissue #1709です。

+を許可した#1248は、Claude CodeのEnterWorktreeツールがworktree名の/を+に変換して生成するブランチ名(例: feat/foo→worktree-feat+foo)が弾かれる報告を受けたものです。worktreeとブランチ名の対応関係そのものはworktree機能の全体像で扱っています。@を許可した#1411は、TICKET-123@add-featureのようなチケット規約や、セッションIDを@<sessionid>で末尾に付与するエージェントツールの命名を通すためのものでした。#1248・#1411などのコミットメッセージは、「execFileSyncを使っているのでインジェクションリスクがない」という同じ根拠を引用しています。

issue #751にそれ以降寄せられたコメント(括弧を含むブランチ名や+の変換)は、それぞれ後続の別PRで個別に対応されました。

現在のホワイトリストで許可される文字と拒否される文字

現行のvalidateBranchName()は次の正規表現を使っています。

const validPattern = /^[a-zA-Z0-9@_][a-zA-Z0-9/_.#+,@()-]*$/;

先頭文字と2文字目以降で許可される集合が異なり、さらに正規表現とは別の個別チェックも組み合わさります。

区分内容
許可(先頭)内容英数字 / @ / _
許可(2文字目以降)内容英数字 / / _ . # + , @ ( ) -
拒否(常に)内容空白、制御文字、~ ^ : ? * [ ] \
拒否(先頭のみ)内容-(CLIオプションとして誤解釈されるのを防ぐため)
拒否(個別ルール)内容先頭・末尾の. / 末尾の/ / 連続する// / 連続する.. / 末尾の.lock / @{を含む / 単独の@

~^:?*[\]や空白はGit自身のgit-check-ref-formatがそもそも禁止している文字で、execFileSync化とは関係なく拒否されます。一方、先頭のダッシュ(-)禁止は「--helpのようなオプションとして誤解釈される」CLIオプションインジェクションへの対策で、シェル経由の注入を防ぐexecFileSync化とは別の理由で意図的に残されています。

@まわりの個別ルールも単純な見た目以上に意味があります。@単独のブランチ名はGitの世界ではHEADの省略記法として解釈され、@{upstream}のような@{...}表記はreflogやリモート追跡ブランチを指す構文です。この2つをホワイトリストで素通りさせると、ブランチ名のつもりで渡した文字列が実際には別のrefを指す式として評価されかねないため、@を許可した#1411でも単独の@と@{を含む名前だけは個別チェックで弾き続けています。この設計は、PR #736で新設されたtest/validate-branch-name.test.tsに反映されており、,を許可した#1310や@を許可した#1411のコミットメッセージでも、緩和と同時に対応するテストケースを追加したことが明記されています。

エラー文言から、当たったルールを読み分ける

現行のvalidateBranchName()は、上から順に検査して最初に当たった項目で止まります。順番は「空」「先頭ダッシュ」「空白・制御文字・特殊文字」「ホワイトリスト」「ピリオド」「末尾スラッシュ」「連続スラッシュ」「..」「.lock」「@{」「単独の@」です。文言の違いは、そのまま原因の違いです。

ログの文言(Invalid branch name: "..."の後ろ)当たったルール
Branch names cannot start with a dash.当たったルール先頭が-
Branch names cannot contain control characters, spaces, or special git characters (~^:?*[\]).当たったルール空白・制御文字・~^:?*[]\
Branch names must start with an alphanumeric character, underscore, or '@' and contain only ...当たったルール許可リスト外の文字(日本語など)
Branch names cannot start or end with a period.当たったルール先頭・末尾の.
Branch names cannot end with a slash.当たったルール末尾の/
Branch names cannot contain consecutive slashes.当たったルール//
Branch names cannot contain '..'当たったルール..
Branch names cannot end with '.lock'当たったルール末尾の.lock
Branch names cannot contain '@{'当たったルール@{
Branch names cannot be the single character '@'.当たったルール単独の@
Branch name cannot be empty(Invalid branch name:の接頭辞なし)当たったルール空のブランチ名

引用符の中に表示されるブランチ名が、実際に検証へ渡された文字列です。名前の見た目に問題がなくても、末尾に半角空白や制御文字が混ざっていれば空白・制御文字の行、全角文字や全角空白が混ざっていれば許可リスト外の行の文言になります。

自分で決めたprefixやテンプレートで当たる場合

Claude Codeが作る側の名前は、変数ごとに整形のされ方が違います。action.ymlの説明では、使える変数は{{prefix}} {{entityType}} {{entityNumber}} {{timestamp}} {{sha}} {{label}} {{description}}の7つです。

くらべる

整形される部分と、そのまま入る部分

label / description

整形される変数

{{label}}は最初のラベルを小文字にし、[a-z0-9-]以外の連続を-に置き換えます。ラベルが無いときはentityTypeになります。{{description}}はタイトルの最初の5語をケバブケースにし、[a-z0-9-]以外は取り除きます。日本語だけのタイトルでは空になります。

prefix / 自分で書いた文字

そのまま入る部分

branch_prefixの値と、テンプレートに直接書いた文字には整形が掛かりません。空白や~、先頭の-を書けば、そのまま検証で止まります。

{{description}}が空になると、{{prefix}}{{description}}/{{entityNumber}}のようなテンプレートはclaude//123になりかねません。実装は連続スラッシュと先頭・末尾のスラッシュを畳んでから検証にかけるので、日本語タイトルのIssueでもここでは止まりません。

今日このエラーに当たったときの対処

手順

切り分けの順序

  1. 1

    参照しているタグを見る

    @v1は新しいリリースのたびに指し先が動くフローティングタグで、上の修正はすべて@v1に入っています。コミットSHAや@v1.0.xの個別タグに固定している場合は、固定した時点より後の修正が入っていません。

  2. 2

    ログの文言を表と照らす

    文言が「must start with an alphanumeric character」を含むなら許可リスト外の文字、それ以外なら表の該当行のルールです。

  3. 3

    ブランチ名かテンプレートのどちらかを直す

    既存のPRブランチが拒否対象の文字を含むなら、名前の側を変えます。claude/以外のbranch_prefixや自作テンプレートが原因なら、with:の設定を見直します。

grep -n "claude-code-action@" .github/workflows/*.yml

固定している個別タグが新しいかどうかは、最初に許可した修正を含むタグで見分けられます。リポジトリのタグを各PRのコミットで逆引きすると、次の対応になります。

通したい文字その文字を許可したPR含む最小のタグ
#その文字を許可したPR#1167含む最小のタグv1.0.89
+その文字を許可したPR#1248含む最小のタグv1.0.105
,その文字を許可したPR#1310含む最小のタグv1.0.123
@その文字を許可したPR#1411含む最小のタグv1.0.155
先頭の_その文字を許可したPR#1486含む最小のタグv1.0.176
()その文字を許可したPR#1710含む最小のタグv1.0.206

たとえばv1.0.150に固定していれば、#・+・,は通りますが、@と括弧は通りません。base_branchとbranch_name_templateの設定例はGitHub ActionsのパラメータとCLI引数をClaude Codeで渡すにあります。導入手順や認証設定はClaude CodeをGitHub Actionsに組み込むが詳しいです。

issueが閉じられなかったのは何を意味するか

issue #751は、登録された2025年12月17日から最後のコメントが付いた2026年4月16日を過ぎてもクローズされず、状態はopenのままです。この間、報告された#の具体例そのものは4月5日の#1167で解消しています。コメント欄では#1024・#998・#1020が別の重複issueとして挙げられており、個々の文字の修正はそれぞれ別issue(#1137・#1244・#1300・#998・#1709)に紐づいてクローズされました。1つのissueに複数の文字種の不満が集まりながら、修正のたびに処理が別issueへ分散した結果、大元の#751だけがopenのまま残っている形です。

対象文字を1つずつ検証し、根拠となるコミットメッセージで毎回execFileSync化による安全性を確認してから追加する、という進め方自体は手堅いものです。ただし利用者から見ると、#が直っても+で同じエラーに当たり、+が直っても括弧で同じエラーに当たるというように、同じ文言のエラーに複数回遭遇しながらバージョンを上げて回避する経験になりやすい構造でもあります。

まとめ

文字ごとに許可されたタグが違うため、固定タグで運用している場合は、使っているブランチ名の文字を表に当てると必要な下限が決まります。#だけならv1.0.89、括弧まで使うならv1.0.206が下限です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. github.com/anthropics/claude-code-action/issues/751
  2. github.com/anthropics/claude-code-action/pull/736
  3. github.com/anthropics/claude-code-action/blob/main/src/github/operati…
  4. github.com/anthropics/claude-code-action/pull/1167
  5. github.com/anthropics/claude-code-action/pull/1710
  6. code.claude.com/docs/en/github-actions
  7. github.com/anthropics/claude-code-action/blob/main/action.yml
  8. github.com/anthropics/claude-code-action/blob/main/src/utils/branch-t…
  9. github.com/anthropics/claude-code-action/blob/main/test/validate-bran…
この記事を共有:XはてブLinkedIn