Skip to content

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

Description

@jgonet

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

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions