Skip to content

fix(renovate): constrain erlang to ^27 so mix.lock updates can run - #141

Merged
toshi0806 merged 1 commit into
mainfrom
fix-renovate-erlang-constraint
Aug 11, 2026
Merged

fix(renovate): constrain erlang to ^27 so mix.lock updates can run#141
toshi0806 merged 1 commit into
mainfrom
fix-renovate-erlang-constraint

Conversation

@toshi0806

Copy link
Copy Markdown
Member

概要

elixir.jsonconstraints.erlang: "^27" を追加し、Renovate による mix.lock 更新が一度も成功していない状態を解消します。

症状

このプリセットを使う 5 リポジトリ(tenbin_dns / tdig / tenbin_ex / tenbin_cache / elixir_dnstap)で、mix の依存更新 PR が以下の 3 点セットで止まっていました。

  • PR の commit status に renovate/artifacts = failure : Artifact file update failure
  • PR コメントに File name: mix.lock / Command failed: install-tool elixir v1.20.3
  • Dependency Dashboard の Repository Problems に ⚠️ WARN: Detected empty commit - aborting git push

git log -- mix.lock を 5 リポジトリすべてで確認したところ、2026-05-23 の Renovate 導入以降、Renovate が mix.lock の更新に成功した記録は一件もありません(それ以前の github-actions[bot] コミットは置換前の別ワークフローによるもの)。

原因

Renovate の mix マネージャ(lib/modules/manager/mix/artifacts.ts)は Erlang と Elixir を非対称に扱います。

const erlangVersion = '26';
...
{ toolName: 'erlang', constraint: config.constraints?.erlang ?? `^${erlangVersion}` },
{ toolName: 'elixir', constraint: config.constraints?.elixir },
  • erlang^26 にハードコードされた既定を持つ
  • elixir は既定制約が無く、mix.exselixir: 要件を満たす最新版まで浮く

対象リポジトリはすべて ~> 1.17(elixir_dnstap は ~> 1.14)なので Elixir 1.20.x が選ばれます。Elixir 1.20 は OTP 27 以上が必須(公開される precompiled zip が otp-27/28/29 のみ)で、^26 の Erlang とは両立しません。

破綻の起点は 2026-06-03 の Elixir 1.20.0 リリースです。それ以前の 1.19.x は OTP 26 に対応していたため成立していました。エラー中の Elixir 版が時期とともに動いていた(7月 v1.20.2 → 8月 v1.20.3)のも、最新を追っている裏付けです。

再現と検証

renovate/renovate イメージ(44.23.3)で対照実験を行いました。変えた変数は Erlang のバージョンのみです。

A: Renovate の既定と同じ組み合わせ

Installing tool erlang@26.2.5.21...  → Install tool erlang succeeded
Installing tool elixir@1.20.3...
ERROR! Unsupported Erlang/OTP version, expected Erlang/OTP 27+
FATAL: Install tool elixir failed

B: 本 PR の設定

Installing tool erlang@27.3.4.15...  → Install tool erlang succeeded
Installing tool elixir@1.20.3...     → Install tool elixir succeeded
Mix 1.20.3 (compiled with Erlang/OTP 27)

再現手順:

docker run --rm --user root --entrypoint bash renovate/renovate -c '
  install-tool erlang 26.2.5.21 && install-tool elixir 1.20.3'

設計上の判断

erlang を制約し、elixir は制約しない。 elixir を低く固定しても、Erlang が ^26 のままなので偶然噛み合うだけで、しかも各プロジェクトが対象としていない Elixir 系列に lockfile 生成を固定してしまいます。

範囲指定(^27)にして特定版に固定しない。 Renovate は containerbase の erlang prebuild に対して制約を解決しますが、これは 4 桁バージョン(27.3.4.1527.3.4 ではない)で公開されています。範囲にしておけば patch リリースを拾い続けます。

CI には影響しません。 本設定は Renovate が lockfile 再生成のために導入する toolchain にのみ効きます。各リポジトリの OTP/Elixir マトリクスは別途 workflow で設定されており、変更されません。

紛らわしい先行事例との切り分け

containerbase #6924(2026-06-16)は elixir.sh の zip 名対応表を直したもので(既定 otp-26 → otp-27)、renovate discussion #38668 の Elixir 1.19 × otp-25 と同型です。症状も時期も似ていますが本件とは別問題で、現行イメージでは既に修正済みであることを確認しています(zip 名は正しく解決されており、落ちているのは Erlang 側)。この混同のため、当初は constraints.elixir での回避を検討していましたが、それでは直りません。

検証済み

  • renovate-config-validator --strict: エラーなし
  • 上記の対照実験 A / B

merge 後の作業

このプリセットは各リポジトリから移動タグ v1 経由で参照されているため、merge しただけでは反映されません。

  1. 新しい semver タグを切る(現在 v1.37.0v1.38.0)。公開済みタグの張り替えは行わない
  2. v1 を新しい main コミットへ張り直す
  3. いずれかのリポジトリで Dependency Dashboard の rebase-branch チェックボックスを ON にし、mix.lock が実際に更新されることを確認する(Renovate は失敗した artifact を自動再試行しないため、既存 PR の赤は失敗時点で凍結しています)

Renovate's mix manager treats its two tools asymmetrically: erlang falls
back to a hardcoded `^26`, while elixir has no default and floats to the
newest release satisfying the `elixir:` requirement in mix.exs. Every
repository on this preset allows `~> 1.17` or wider, so Renovate picks
Elixir 1.20.x -- which requires OTP 27+ and refuses to install against
OTP 26.

Reproduced with the renovate/renovate image (44.23.3):

  install-tool erlang 26.2.5.21   -> succeeded
  install-tool elixir 1.20.3      -> ERROR! Unsupported Erlang/OTP
                                     version, expected Erlang/OTP 27+

Renovate surfaces that as `Command failed: install-tool elixir v1.20.3`,
leaves mix.lock untouched, and drops the resulting empty commit
(`Detected empty commit - aborting git push`). No mix lock file update
has succeeded since Elixir 1.20.0 was released on 2026-06-03.

Swapping only the erlang version fixes it:

  install-tool erlang 27.3.4.15   -> succeeded
  install-tool elixir 1.20.3      -> succeeded (Mix 1.20.3)

This affects only the toolchain Renovate installs to regenerate lock
files; each repository's CI matrix is configured separately.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全体的に変更の意図が明確で、PR説明も詳細です。1点だけ指摘します。

Comment thread elixir.json
"Raise the Erlang/OTP floor used to regenerate mix.lock. Renovate's mix manager treats its two tools asymmetrically: erlang falls back to a hardcoded `^26` (lib/modules/manager/mix/artifacts.ts), while elixir has no default and floats to the newest release satisfying the `elixir:` requirement in mix.exs. Every repository here allows `~> 1.17` or wider, so Renovate picks Elixir 1.20.x -- which requires OTP 27+ and refuses to install against OTP 26. The install step then aborts with `ERROR! Unsupported Erlang/OTP version, expected Erlang/OTP 27+`, Renovate reports `Command failed: install-tool elixir vX.Y.Z`, mix.lock is left untouched, and the resulting empty commit is dropped (`Detected empty commit - aborting git push`). Every mix lock file update has failed this way since Elixir 1.20.0 was released on 2026-06-03.",
"Constrain erlang rather than elixir. Pinning elixir low would only avoid the mismatch by accident, and would freeze lock file generation on an Elixir line the projects no longer target. This affects only the toolchain Renovate installs to regenerate lock files; the OTP/Elixir matrix in each repository's CI is configured separately and is unchanged.",
"Do not narrow this to an exact version. Renovate resolves the constraint against containerbase's erlang prebuilds, which are published as four-component versions (27.3.4.15, not 27.3.4); a range keeps picking up their patch releases."
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [MEDIUM] description フィールドに非常に長い技術的背景説明が含まれています。Renovate の description はダッシュボードや PR コメントに表示される設定の概要を示すためのものであり、このような詳細な根拠・経緯の記述は通常 PR 本文や CHANGELOG に置くべきです。

設定ファイル内に長文の説明を埋め込むと、将来の保守担当者が設定の全体像を把握しにくくなります。description は簡潔な1〜2文程度に留め、詳細は PR 本文や別ドキュメントを参照するよう案内する形が望ましいです。

例:

"description": [
  "Constrain Erlang to ^27 so Renovate can regenerate mix.lock with Elixir 1.20+, which requires OTP 27+."
]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

裏取りしたうえで、据え置きます。根拠を 2 点挙げます。

1. 指摘の前提が事実と異なります

description はダッシュボードや PR コメントに表示される設定の概要を示すためのもの」とありますが、Renovate 本体の定義(lib/config/options/index.ts:451)はこうなっています。

{
  name: 'description',
  description: 'Plain text description for a config or preset.',
  type: 'array',
  subType: 'string',
  stage: 'repository',
  ...
}

「config または preset のプレーンテキスト説明」とあるだけで、Dependency Dashboard や PR コメントへの表示については記述がありません。表示先が限られるという前提が成り立たないため、「簡潔にすべき」という結論もそこからは導けません。

2. 長文の description はこのリポジトリの確立した慣行です

本 PR の書き方は既存プリセットと同じで、むしろ揃えにいったものです。

ファイル top-level description 最長
default.json 3 項目 734 文字
latex.json 3 項目 634 文字
template.json 2 項目 397 文字
default.jsonpackageRules[1] 771 文字
elixir.json の既存 packageRules[0] 535 文字
本 PR の elixir.json 3 項目 825 文字

default.jsonplatformAutomerge: false を選んだ理由、automergeStrategy: "squash" の理由、osvVulnerabilityAlerts を使う理由をそれぞれ数百文字で書いています。ご提案の 1〜2 文形式に本 PR だけ合わせると、かえってこのリポジトリの中で浮きます。

なぜこの内容をファイル内に置くのか

constraints.erlang は、背景を知らない人が「不要な固定に見える」として消しやすい設定です。実際これは 2026-05-23 の Renovate 導入以降 mix.lock 更新が一度も成功していなかった原因そのもので、消せば再び全リポジトリで静かに壊れます。PR 本文はファイルを開いた人の視界に入りませんが、description は入ります。再発しやすさに対して説明の置き場所を選んでいる、という判断です。

なお挙動には影響しない項目で、renovate-config-validator --strict も通過しています。以上より、コード変更なしで据え置きます。

@toshi0806

Copy link
Copy Markdown
Member Author

レビュー対応まとめ

指摘 1 件、いずれも根拠を確認したうえで据え置きとしました。コード変更はありません。

# 指摘 対応
[MEDIUM] description が長すぎる。1〜2 文に留め詳細は PR 本文へ 据え置き(返信

据え置きの理由は 2 点です。

  1. 指摘の前提が事実と異なる — Renovate 本体の定義(lib/config/options/index.ts:451)は description'Plain text description for a config or preset.' としているだけで、「ダッシュボードや PR コメントに表示される」という記述はありません
  2. 長文の description は本リポジトリの確立した慣行default.json(3 項目・最長 734 文字)、latex.json(3 項目・634 文字)、template.json(2 項目・397 文字)、default.jsonpackageRules[1](771 文字)がいずれも同じ形式。本 PR(3 項目・825 文字)だけ 1〜2 文にすると逆に不揃いになります

CI

チェック 結果
review / review ✅ success
actionlint ✅ success

merge 後に必要な作業

このプリセットは各リポジトリから移動タグ v1 経由で参照されているため、merge しただけでは反映されません

  1. 新しい semver タグを切る(現在 v1.37.0v1.38.0)。公開済みタグの張り替えは行わない
  2. v1 を新しい main コミットへ張り直す
  3. いずれかのリポジトリで Dependency Dashboard の rebase-branch チェックボックスを ON にし、mix.lock が実際に更新されることを確認する(Renovate は失敗した artifact を自動再試行しないため、既存 PR の赤は失敗時点で凍結しています)

3 まで終えて初めて完了です。

@toshi0806
toshi0806 merged commit 5f831bf into main Aug 11, 2026
3 checks passed
@toshi0806
toshi0806 deleted the fix-renovate-erlang-constraint branch August 11, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant