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.対象になるのは、これから作る新しいブランチ名ではなく、すでにリポジトリに存在するPRのheadブランチやbaseブランチです。issueで最初に報告された例は#8982-bugfixで、以後feature/#12345-some-name(GitHubのIssue番号を先頭に含む命名規則)やfix(scope)/the-branch-name(Conventional Commits風のスコープ表記)、put-back-arm64-#2など、Gitとしては正当なのに拒否される命名パターンが複数報告されています(issue #751)。
issueのコメント欄には実運用での影響も具体的に書き込まれています。ある投稿者は、Issue番号をブランチ名に含める社内規則があるためGitHub Actions上のPRレビューが軒並み失敗すると報告し、別の投稿者は最終的にclaude-code-actionの利用をやめてCopilotなど他のPRレビューbotへ乗り換えたとコメントしました。ブランチ命名規則を自社のCIツールの都合で変えるのは現実的でないため、当時は代替のブランチ命名テンプレートに切り替える運用回避策も共有されていました。
検証はsetupBranch()という関数の中で3つの経路に対して呼ばれます。PRイベントで動くときはheadブランチ(branchName)を検証してからチェックアウトし、PRがopenであればマージ先のbaseブランチ(prData.baseRefName)も追加で検証します。Issueイベントで新規ブランチを作るときは、分岐元になるソースブランチと、これから作る新しいブランチの両方が対象です。Claude Codeが自分で生成するブランチ名はbranch_name_template(既定値{{prefix}}{{entityType}}-{{entityNumber}}-{{timestamp}})から作られ、英数字とハイフンだけで構成されるため通常はこの検証で引っかかりません。エラーが起きるのは、ユーザー側がすでに作っていた既存ブランチをPRトリガーで読み込む場面がほとんどです。
エラーの原因 — コマンドインジェクション対策のホワイトリスト
この検証は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のコミット履歴を見ると、次の順で許可文字が広がっています。
| マージ日 | PR | 追加された文字 | きっかけのissue |
|---|---|---|---|
| 2026-04-05 | PRPR #1167 | 追加された文字# | きっかけのissue#1137 |
| 2026-04-23 | PRPR #1248 | 追加された文字+ | きっかけのissue#1244 |
| 2026-05-14 | PRPR #1310 | 追加された文字,(カンマ) | きっかけのissue#1300 |
| 2026-06-22 | PRPR #1411 | 追加された文字@(先頭位置含む) | きっかけのissue#998 |
| 2026-07-16 | PRPR #1486 | 追加された文字先頭のアンダースコア | きっかけのissue— |
| 2026-08-25 | PRPR #1710 | 追加された文字括弧 () | きっかけのissue#1709 |
+を許可した#1248は、Claude CodeのEnterWorktreeツールがworktree名の/を+に変換して生成するブランチ名(例: feat/foo→worktree-feat+foo)が弾かれる報告を受けたものです。worktreeとブランチ名の対応関係そのものはworktree機能の全体像で扱っています。@を許可した#1411は、TICKET-123@add-featureのようなチケット規約や、セッションIDを@<sessionid>で末尾に付与するエージェントツールの命名を通すためのものでした。いずれのコミットメッセージも「execFileSyncを使っているのでインジェクションリスクがない」という同じ根拠を繰り返し引用しており、拡張の判断基準が一貫していたことがうかがえます。
なお、issue #751自体で報告された#8982-bugfixのケースは、2026年4月5日にマージされた#1167の時点で解消しています。それ以降にissueへ寄せられたコメント(括弧を含むブランチ名や+の変換)は、それぞれ後続の別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のコミットメッセージでも、緩和と同時に対応するテストケースを追加したことが明記されています。
今日このエラーに当たったときの対処
まず確認すべきは、ワークフローでclaude-code-actionをどう固定しているかです。@v1は最新リリースが出るたびに指し先が更新されるフローティングタグとして運用されており、上の修正PRはすべて@v1にすでに取り込まれています。特定のコミットSHAや、フローティングでない古い個別バージョンタグに固定している場合は、そこに該当の修正が含まれていない可能性があります。
grep -n "claude-code-action@" .github/workflows/*.yml@v1や十分新しい@v1.0.xを指していればホワイトリストは最新のはずです。それでも「Invalid branch name」が出る場合は、ブランチ名が上の表の「拒否」区分に該当していないかを確認します。空白や~^:?*[\]を含む名前、先頭がダッシュや連続ピリオドになっている名前は現行版でも拒否対象です。この場合はブランチ名を変更するか、base_branchやbranch_name_templateなどwith:パラメータ全体の設定を見直す必要があります。base_branchとbranch_name_templateの設定例はGitHub ActionsのパラメータとCLI引数をClaude Codeで渡すにまとめています。claude-code-action自体の導入手順や認証設定は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化による安全性を確認してから追加する、という進め方自体は手堅いものです。ただし利用者から見ると、#が直っても+で同じエラーに当たり、+が直っても括弧で同じエラーに当たるというように、同じ文言のエラーに複数回遭遇しながらバージョンを上げて回避する経験になりやすい構造でもあります。
まとめ
claude-code-actionの「Invalid branch name」エラーは、PR #736で導入されたコマンドインジェクション対策のホワイトリストが発端です。#・+・,・@・括弧は、2026年4月から8月にかけて#1167・#1248・#1310・#1411・#1710の各PRで個別に許可され、いずれも「execFileSyncを使うためシェル経由の注入リスクがない」という同じ理由で緩和されました。@v1のようなフローティングタグを使っていれば現在はこれらの文字を含むブランチ名で失敗することはなく、それでもエラーが出る場合は空白や~^:?*[\]、先頭ダッシュなど、今も意図的に拒否されている文字がブランチ名に含まれていないかを確認するのが最短の対処です。