erlef / erlef/setup-beam

Multiple instances of erlef/setup-beam install to the same directory

Open
#493 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
JavaScript
Stars
454
Forks
88
PR merge metrics
No merged PRs in 30d

Description

#### The bug

Two uses of erlef/setup-beam installs OTP to the same directory, clobbering files.

#### Software versions

Current main: https://github.com/erlef/setup-beam/blob/8736e9244717f9207464c14c6051b71d22253f60/src/setup-beam.js#L1262-L1266

#### 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:-}"
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).

Contributor guide

Open the contributing guide

Research direction

Start with src/setup-beam.js at lines 1262-1266, then run the reproduction in .github/workflows/setup_beam_double_install.yml. Inspect the installation root after both OTP installs and compare it with the expected behavior: separate versioned roots or an error when the directory is non-empty.

Written by the indexing model from the issue text.

Assessment

Tech stack
erlang, github-actions, javascript
Domain
ci-cd, devops
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.