Elixir OTP version mismatch ".beam file was compiled" in CI
BEAM bytecode is tied to the OTP major it was compiled under. When a restored _build cache was built with a different OTP than the runner now has, the VM refuses the .beam files and compilation breaks.
What this error means
After bumping otp-version (or a cache from another job), the build fails loading modules that "were compiled for a different version" of Erlang/OTP.
** (Mix)
** (exit) :badfile
module was compiled for a different version of the Erlang runtime systemCommon causes
Restored _build cache built under a different OTP
actions/cache restored _build compiled with an older OTP major; the new runner OTP cannot load those beams.
Cache key does not include the OTP/Elixir version
A key keyed only on mix.lock reuses artifacts across toolchain bumps, so stale beams leak into the new environment.
How to fix it
Key the cache on OTP and Elixir versions
- Include the OTP and Elixir versions (and MIX_ENV) in the cache key.
- Bumping either version then produces a fresh cache instead of reusing stale beams.
- Cache deps and _build separately so a rebuild is cheap.
.github/workflows/ci.yml
- uses: actions/cache@v4
with:
path: |
deps
_build
key: mix-${{ runner.os }}-otp${{ steps.beam.outputs.otp-version }}-elixir${{ steps.beam.outputs.elixir-version }}-${{ hashFiles('**/mix.lock') }}Force a clean compile when in doubt
Clear the build directory so nothing stale from another OTP is loaded.
Terminal
mix deps.clean --all
mix clean
mix deps.get && mix compileHow to prevent it
- Put OTP and Elixir versions in the _build cache key.
- Give setup-beam an id and read its version outputs into the key.
- Rebuild from clean when bumping the toolchain.
Related guides
erlef/setup-beam "no version found matching" in CIFix erlef/setup-beam "Error: no version found matching" in CI - the requested Elixir or OTP version does not…
Elixir "mix: command not found" (setup-beam) in CIFix "mix: command not found" in CI - the runner has no Elixir/OTP on PATH because erlef/setup-beam was skippe…
Elixir "protocol has not been consolidated" warning in CIFix "the protocol X has not been consolidated" in CI - a restored _build reused stale protocol consolidation,…