GitHub API の 404 エラー:原因と解決策
冒頭まとめ GitHub API の 404 Not Found には、二重の意味があります。指定したリソースが本当に存在しない場合と、存在するが権限がなくて見せてもらえない場合です。公式ドキュメントに明記されているとおり、GitHub は非公開リポジトリの存在を外部に確認させないために、認証や権限の不備に対して 403 Forbidden ではなく 404 を返す設計を採っています。つまり、リソースがあるはずなのに404が出たら、まず疑うべきは URL ではなく認証と権限です。 原因は3系統に整理できます。URL の指定誤り(タイポ・末尾スラッシュ・エンコード漏れ)、認証の不備(トークン未指定・期限切れ・失効)、そして認証は通っているがトークンの権限が足りない場合です。切り分けの起点は、同じ形のリクエストを条件を変えて比べることです。 エラーの概要 GitHub API の404の応答本文は次の形です。status の値は数値ではなく文字列である点に注意してください。 { "message": "Not Found", "documentation_url": "https://docs.github.com/rest/repos/repos#get-a-repository", "status": "404" } documentation_url は、GitHub がそのリクエストをどのエンドポイントとして解釈したかを示す手がかりです。意図と違うエンドポイントのリファレンスが返ってきている場合は、URL の形そのものを取り違えています。意図どおりのリファレンスが返っているのに404なら、対象の存在か権限の問題です。 権限の問題が404として現れるのは GitHub の意図的な設計です。もし権限不足に403を返すと、404との違いから「そのリポジトリは存在する(が見られない)」という情報が漏れてしまいます。これを防ぐため、非公開リソースへの適切に認証されていないリクエストには、存在しない場合と同じ404を返します。診断する側から見ると、404は「無い」と「見せてもらえない」を区別してくれないコードだ、と理解しておくことが出発点になります。 まず最初に:条件を変えて同じリクエストを比べる 404の原因を推測する前に、2つの比較で範囲を絞れます。 第一に、トークン自体の生死を確認します。認証済みユーザー自身の情報を返すエンドポイントを叩きます。 curl -i -H "Authorization: Bearer <your-github-token>" https://api.github.com/user 200 が返ればトークンは有効です。401 Unauthorized(Bad credentials)が返るなら、トークンの値の誤りや失効であり、404とは別の問題として先に解決します。 第二に、確実に存在する公開リポジトリに対して、調べたいものと同じ形のリクエストを送ります。 curl -i https://api.github.com/repos/octocat/Hello-World これが通るなら URL の組み立て方は正しく、問題は対象リソースの側(存在または権限)に絞られます。これも404になるなら、URL の形そのものを疑います(原因1)。 よくある原因と解決手順 原因1:URL の指定誤り オーナー名・リポジトリ名・ファイルパスの綴りの誤りは、そのまま404になります。ファイル名は思い込みが入りやすい箇所です。たとえば microsoft/vscode リポジトリのライセンスファイルは LICENSE.md ではなく LICENSE.txt であり、拡張子を誤ると404が返ります。 Before(ファイル名の思い込みで404): curl -H "Authorization: Bearer <your-github-token>" \ https://api.github.com/repos/microsoft/vscode/contents/LICENSE.md After(実際のファイル名を確認して指定): curl -H "Authorization: Bearer <your-github-token>" \ https://api.github.com/repos/microsoft/vscode/contents/LICENSE.txt ファイル名の確認には、親ディレクトリの一覧取得(/contents/ をパスなしで叩く)や、ブラウザでのリポジトリの目視が確実です。 ...