The bug
Two uses of erlef/setup-beam installs OTP to the same directory, clobbering files.
Software versions
Current main:
|
const runnerToolPath = path.join( |
|
process.env.RUNNER_TEMP, |
|
'.setup-beam', |
|
toolName, |
|
) |
How to replicate
You can check this log: https://github.com/software-mansion/popcorn/actions/runs/31215221447/job/92987074922
Check those two lines (size changed):
# after OTP 26
-rwxr-xr-x 1 runner runner 540376 Aug 7 20:17 erlc
# after OTP 28
-rwxr-xr-x 1 runner runner 542840 Aug 7 20:17 erlc
and
=== apps present in more than one version ===
asn1:
/home/runner/work/_temp/.setup-beam/otp/lib/asn1-5.1
/home/runner/work/_temp/.setup-beam/otp/lib/asn1-5.4.2
(...)
Full workflow file
### Repro for erlef/setup-beam: two installs in one job share $RUNNER_TEMP/.setup-beam
###
### The second install copies over the first instead of replacing it. Files that
### exist in both (bin/erl, ...) are overwritten, but version-suffixed app
### directories from the first install survive, so $ROOT/lib ends up holding two
### OTP releases at once.
###
### The inspection after the first install doubles as the control: at that point
### $ROOT/lib holds exactly one version of each app.
name: setup-beam double install repro
on:
workflow_dispatch:
push:
paths:
- ".github/workflows/setup_beam_double_install.yml"
permissions:
contents: read
jobs:
repro:
name: Two setup-beam installs in one job
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Install OTP 26.0.2
uses: erlef/setup-beam@8736e9244717f9207464c14c6051b71d22253f60 # main @ 2026-07-08
with:
otp-version: "26.0.2"
- name: Inspect after installing OTP 26.0.2
run: &inspect |
set -uo pipefail
root="$(erl -noshell -eval 'io:format("~s", [code:root_dir()]), halt().')"
echo "RUNNER_TEMP = ${RUNNER_TEMP}"
echo "INSTALL_DIR_FOR_OTP = ${INSTALL_DIR_FOR_OTP:-<unset>}"
echo "code:root_dir() = ${root}"
erl -noshell -eval \
'io:format("otp_release=~s erts=~s~n", [erlang:system_info(otp_release), erlang:system_info(version)]), halt().'
echo
echo "=== ${root}/bin ==="
ls -la "${root}/bin"
echo
echo "=== ${root}/lib ==="
ls -1 "${root}/lib"
echo
echo "=== ${root}/releases ==="
ls -1 "${root}/releases"
for f in "${root}"/releases/*/OTP_VERSION; do
[ -f "${f}" ] && echo " ${f} -> $(cat "${f}")"
done
echo
echo "=== ${root}/erts-* ==="
ls -1d "${root}"/erts-* 2>/dev/null || echo " none"
echo
echo "=== apps present in more than one version ==="
duplicated="$(ls -1 "${root}/lib" | sed -E 's/-[0-9][0-9.]*$//' | sort | uniq -d)"
if [ -z "${duplicated}" ]; then
echo " none"
else
printf '%s\n' "${duplicated}" | while IFS= read -r app; do
echo " ${app}:"
ls -1d "${root}/lib/${app}"-* | sed 's/^/ /'
done
fi
- name: Install OTP 28.3.1
uses: erlef/setup-beam@8736e9244717f9207464c14c6051b71d22253f60 # main @ 2026-07-08
with:
otp-version: "28.3.1"
- name: Inspect after installing OTP 28.3.1
run: *inspect
Expected behaviour
Either:
- versioned installation root
- an error when dir is non-empty
Additional context
When working on Popcorn (which does some shenanigans with .app files) I noticed that we were getting apps not compatible with desired OTP version.
This turned out to be problem with having two erlef/setup-beam, with different versions (one was installed from our composite action which wasn't apparent when looking at final GHA).
The bug
Two uses of erlef/setup-beam installs OTP to the same directory, clobbering files.
Software versions
Current main:
setup-beam/src/setup-beam.js
Lines 1262 to 1266 in 8736e92
How to replicate
You can check this log: https://github.com/software-mansion/popcorn/actions/runs/31215221447/job/92987074922
Check those two lines (size changed):
and
Full workflow file
Expected behaviour
Either:
Additional context
When working on Popcorn (which does some shenanigans with .app files) I noticed that we were getting apps not compatible with desired OTP version.
This turned out to be problem with having two erlef/setup-beam, with different versions (one was installed from our composite action which wasn't apparent when looking at final GHA).