できない.dev

Maven「Blocked mirror for repositories」の原因と直し方

Blocked mirror for repositories は、http:// のリポジトリ URL を https:// に直せば解消する。
Maven 3.8.1 以降は、外部の HTTP リポジトリへの取得を既定で止めている。

公開:

要約

pom.xml に http:// のリポジトリを書き、Maven Central に無い依存をそこから取ろうとすると、ビルドが依存の取得で止まる。
Maven 3.10.0 では次のように出る。

[ERROR] Failed to execute goal on project app: Could not collect dependencies for project com.example:app:jar:1.0
[ERROR] Failed to read artifact descriptor for com.example.legacy:legacy-lib:jar:1.0
[ERROR] 	Caused by: The following artifacts could not be resolved: com.example.legacy:legacy-lib:pom:1.0 (absent): Could not transfer artifact com.example.legacy:legacy-lib:pom:1.0 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [legacy (http://repo.example.com/maven2, default, releases+snapshots)]

Blocked mirror for repositories は、HTTP のリポジトリへの取得を Maven 自身が止めたという意味だ。
Maven 3.8.1 から、暗号化されていない HTTP の外部リポジトリは既定でブロックされる。
通信の途中で依存をすり替えられる危険があるためだ(Maven 3.8.1 のリリースノート(新しいタブで開く))。

止めているのは、Maven 本体の conf/settings.xml にある次の mirror だ。external:http:* は「localhost 以外で、HTTP を使うすべてのリポジトリ」を指す。http://0.0.0.0/ はブロック用の見かけの URL で、実際にはそこへ接続しない。

<mirror>
  <id>maven-default-http-blocker</id>
  <mirrorOf>external:http:*</mirrorOf>
  <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
  <url>http://0.0.0.0/</url>
  <blocked>true</blocked>
</mirror>

エラーの角括弧の中に、止められたリポジトリの ID と URL が出る。
ここを見て、どのリポジトリを直すかを決める。

解決策

1. URL を https:// に直す

そのリポジトリが HTTPS でも配信されているなら、URL を書き換えるだけでよい。

<repositories>
  <repository>
    <id>legacy</id>
    <url>https://repo.example.com/maven2</url>
  </repository>
</repositories>

Maven 3.10.0 で書き換えて実行し直すと、取得先は maven-default-http-blocker ではなく legacy (https://repo.example.com/maven2) に変わった。

2. 依存の POM が原因なら、バージョンを上げるか mirror で向け直す

リリースノートが示す直し方は 2 つある。
HTTPS の URL に直った新しいバージョンへ依存を上げるか、バージョンはそのままで settings.xml に mirror を書くかだ。
mirror は、止められたリポジトリの ID を <mirrorOf> に書き、HTTPS の URL へ向ける(Using Mirrors for Repositories(新しいタブで開く))。

<settings>
  <mirrors>
    <mirror>
      <id>legacy-https</id>
      <mirrorOf>legacy</mirrorOf>
      <url>https://repo.example.com/maven2</url>
    </mirror>
  </mirrors>
</settings>

Maven 3.10.0 で ~/.m2/settings.xml にこれを置くと、取得先が legacy-https (https://repo.example.com/maven2) に切り替わった。

3. 社内リポジトリは HTTPS にする

社内の Nexus などが HTTP でしか使えないなら、HTTPS で公開してもらうのが筋だ。
同じマシンで動かしている http://localhost のリポジトリは external:http:* の対象外で、Maven 3.10.0 でもブロックされずに接続しに行った。

よくある原因

  1. pom.xml に http:// の URL を書いている。
    古い手順書から写したリポジトリの URL が http:// のままになっている。
  2. settings.xml のプロファイルに書いている。~/.m2/settings.xml で足したリポジトリも、HTTP なら同じように止められる。
  3. 依存ライブラリの POM に書かれている。
    自分では書いていなくても、依存の POM が HTTP のリポジトリを宣言していれば、その先の依存の取得で止まる。
    リリースノートの例では、エラーに Failed to collect dependencies at A -> B のような依存の経路が出る。
  4. 社内リポジトリが HTTP のままになっている。
    Nexus などを http:// で運用している。

なお、Maven 3.10.0 で http:// のリポジトリを書いた pom.xml に、Maven Central にある依存だけを書いた場合は、Central から取れて BUILD SUCCESS になった。
止まったのは、Central に無い依存を取りに行ったときだけだった。