Dialyzer failure when running in GitHub actions - includes MacOS paths for Ubuntu build

I’m working my way through Engineering Elixir Applications and I’m running into an issue that I hope is something easy. I’m on page 103 if anyone else has the book. Workstation used for running through the examples: M1 Mac.

When running the Github Action it fails with the following:

Run mix dialyzer --format github
  mix dialyzer --format github
  shell: /usr/bin/bash -e {0}
  env:
    MIX_ENV: test
    INSTALL_DIR_FOR_OTP: /home/runner/work/_temp/.setup-beam/otp
    INSTALL_DIR_FOR_ELIXIR: /home/runner/work/_temp/.setup-beam/elixir
Finding suitable PLTs
Checking PLT...
[:asn1, :bandit, :castore, :compiler, :crypto, :dns_cluster, :eex, :elixir, :ex_unit, :expo, :finch, :floki, :gettext, :hpax, :jason, :kanban, :kernel, :logger, :mime, :mint, :nimble_options, :nimble_pool, :phoenix, :phoenix_html, :phoenix_live_dashboard, :phoenix_live_view, :phoenix_pubsub, :phoenix_template, :plug, :plug_crypto, :public_key, :runtime_tools, :ssl, :stdlib, :swoosh, :telemetry, :telemetry_metrics, :telemetry_poller, :thousand_island, :websock, :websock_adapter, :xmerl]
Looking up modules in project.plt
Finding applications for project.plt
Finding modules for project.plt
Removing 1374 modules from project.plt
:dialyzer.run error: File not found: /opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/dialyzer-5.1.3/ebin/erl_bif_types.beam

Adding 1338 modules to project.plt
:dialyzer.run error: File not found: /opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/dialyzer-5.1.3/ebin/erl_bif_types.beam

done in 0m3.53s
No :ignore_warnings opt specified in mix.exs and default does not exist.

Starting Dialyzer
[
  check_plt: false,
  init_plt: ~c"/home/runner/work/kanban/kanban/priv/plts/project.plt",
  files: [~c"/home/runner/work/kanban/kanban/_build/test/lib/kanban/ebin/Elixir.Kanban.Application.beam",
   ~c"/home/runner/work/kanban/kanban/_build/test/lib/kanban/ebin/Elixir.Kanban.Mailer.beam",
   ~c"/home/runner/work/kanban/kanban/_build/test/lib/kanban/ebin/Elixir.Kanban.beam",
   ~c"/home/runner/work/kanban/kanban/_build/test/lib/kanban/ebin/Elixir.KanbanWeb.ConnCase.beam",
   ~c"/home/runner/work/kanban/kanban/_build/test/lib/kanban/ebin/Elixir.KanbanWeb.CoreComponents.beam",
   ...],
  warnings: [:unknown]
]
:dialyzer.run error: File not found: /opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/dialyzer-5.1.3/ebin/erl_bif_types.beam
Halting VM with exit status 1

From the book I’ve setup the following workflow (ci_cd.yaml below, as of page 103 for those that have it).

# in ci_cd.yaml

name: CI/CD Elixir

on:
  push:
  workflow_dispatch:

jobs:
  ci:
    runs-on: ubuntu-latest
    name: Compile with mix test, format, dialyzer & unused deps check
    env:
      MIX_ENV: test
    steps:
      - uses: actions/checkout@v4

      - name: Setup Elixir
        uses: erlef/setup-beam@v1.17.3
        with:
          version-file: .tool-versions
          version-type: strict

      - name: Cache deps directory
        uses: actions/cache@v4
        id: cache-deps
        with:
          path: |
            deps
            _build
          key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
          restore-keys: |
            ${{ runner.os }}-mix-

      - name: Cache plt files
        uses: actions/cache@v4
        env: 
          EX_OTP_VERSIONS: ${{ steps.setup-beam.outputs.elixir-version }}
          KEY_BASE: plt-${{ runner.os }}-${{ env.EX_OTP_VERSIONS }}
        with:
          path: |
            priv/plts
          key: |
            ${{ env.KEY_BASE }}-${{ hashFiles('**/mix.lock') }}
          restore-keys: |
            ${{ env.KEY_BASE }}-

      - name: Get dependencies
        if: steps.cache-deps.outputs.cache-hit != 'true'
        run: mix deps.get

      - run: mix compile

      - name: Run tests
        run: mix test --max-failures 1 --trace

      - name: Check code is formatted
        run: mix format --check-formatted

      - name: Dialyzer static analysis
        run: MIX_ENV=dev mix dialyzer --format github

      - name: Check unused dependencies
        run: mix deps.unlock --check-unused

As seen above this Workflow runs-on: ubuntu-latest. From the Workflow errors we’re calling for a file in the path of /opt/homebrew/Cellar/ and failing, because this isn’t macOS (I’m unaware of another homebrew tool)

In my .gitignore I have the following:

# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version 
# control as they are data points which are potentially sensitive and subject 
# to change depending on the environment.
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc

# Typical Elixir ignore files
/_build
/cover
/deps
/doc
/.fetch
erl_crash.dump
*.ez
*.beam
/config/*.secret.exs
.elixir_ls/

/priv/plts/*.plt
/priv/plts/*.plt.hash

So - I’d expect deps and _build cache to not be present (and they aren’t in my repo). When I search for Cellar in my local (macOS) working directory grep -Rnw ‘.’ -e ‘Cellar’ I see:

Binary file ./_build/test/lib/floki/ebin/floki_selector_lexer.beam matches
Binary file ./_build/test/lib/erlex/ebin/erlex_parser.beam matches
Binary file ./_build/test/lib/erlex/ebin/erlex_lexer.beam matches
Binary file ./_build/dev/lib/erlex/ebin/erlex_parser.beam matches
Binary file ./_build/dev/lib/erlex/ebin/erlex_lexer.beam matches
./deps/floki/src/floki_selector_lexer.erl:1:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 0).
./deps/floki/src/floki_selector_lexer.erl:30:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 14).
./deps/floki/src/floki_selector_lexer.erl:1340:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 344).
./deps/erlex/src/erlex_parser.erl:7:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/yeccpre.hrl", 0).
./deps/erlex/src/erlex_lexer.erl:1:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 0).
./deps/erlex/src/erlex_lexer.erl:17:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 14).
./deps/erlex/src/erlex_lexer.erl:851:-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/leexinc.hrl", 344).

Spot checking ./deps/erlex/src/erlex_parser.erl:7 I see:

-module(erlex_parser).
-export([parse/1, parse_and_scan/1, format_error/1]).
-file("src/erlex_parser.yrl", 137).

unwrap({_,_,V}) -> V.

-file("/opt/homebrew/Cellar/erlang/26.2.5/lib/erlang/lib/parsetools-2.5/include/yeccpre.hrl", 0).

I’m a little lost on how my dialyzer.run via Github action is failing with the missing file error. If the ubuntu-latest is downloading / building the dependancies on that virtual machine then how is it failing / looking for Cellar/homebrew file locations? As shown above when I search from the root of my project I’m only seeing the matching results in my _build and deps folders - which are excluded.

Happy to add snippets of other files or anything to help me track this down. Thanks for the time if you’ve made it this far.

I’ll also note that I have removed the cache from the job to see if that would make a difference - to no avail.