Skip to content

Conversation

@giddie
Copy link
Contributor

@giddie giddie commented Jan 29, 2026

For anyone running the LSP in a dev container or otherwise simplified environment, we cannot rely on the presence of SHELL or the behaviour of a login shell to provide a clean PATH. I propose we instead filter out the RELEASE_ROOT from PATH, which seems to adequately address the issue of using the correct paths for ASDF/mise.

@mhanberg
Copy link
Member

Would you be able to point me to documentation as to how the RELEASE_ROOT variable works and what it does?

@giddie
Copy link
Contributor Author

giddie commented Jan 30, 2026

Sure! It looks like it's part of the ERTS release machinery. In the Mix docs:

The system sets different environment variables. The following variables are set early on and can only be read by env.sh and env.bat:

  • RELEASE_ROOT - points to the root of the release. If the system includes ERTS, then it is the same as :code.root_dir/0. This variable is always computed and it cannot be set to a custom value
    [...]

Note that "can only be read" here means "not written" (as opposed to "can be read only here"). That threw me at first glance.

It looks like it's set in apps/expert/_build/prod/rel/plain/bin/plain, line 14:

SELF=$(readlink_f "$0")
RELEASE_ROOT="$(CDPATH='' cd "$(dirname "$SELF")/.." && pwd -P)"

So RELEASE_ROOT=apps/expert/_build/prod/rel/plain

And the reason we want to use it for filtering is that PATH gets set like this:

The $REL_VSN_DIR/elixir script calls $ERTS_BIN/erl, which sets BINDIR:

BINDIR="$(cd "$(dirname "$SELF")" && pwd -P)"

So BINDIR=apps/expert/_build/prod/rel/plain/erts-16.2/bin
(Which is equivalent to $RELEASE_ROOT/erts-16.2/bin.)

And then calls $BINDIR/erlexec, which prepends BINDIR to PATH. (Link to OTP C source.)

So I think what's happening is that when invoking the project Elixir, it's seeing the wrong erl -- the one from BINDIR. And that causes the project to fail boot. Since RELEASE_ROOT seems like a pretty stable feature it seems like a good way to filter out the added BINDIR from PATH as well as anything else that ERTS may inject in there in future. Less brittle than launching a login shell, in my opinion.

We cannot rely on the presence of SHELL or the behaviour of a login
shell because these things are often not available inside containers.
@giddie giddie force-pushed the filter-path-instead-of-login-shell branch from bb0285a to 0ec44ad Compare January 30, 2026 11:54
@giddie giddie changed the title Filter out RELEASE_ROOT from PATH instead of running a login shell fix: filter out RELEASE_ROOT from PATH instead of running a login shell Jan 30, 2026
Copy link
Collaborator

@doorgan doorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this with mise and asdf on macos and it is working. It's essentially the same approach I used to fix it for windows, but I no longer recall if or why it didn't work on unix back when I first was figuring this out months ago.

At this point I think getting rid of the release root in the path is the way to go but I'd like someone using nix/fish/nushell to try this too before merging

@mhanberg
Copy link
Member

@doorgan there were a number of release related env vars id filter out in next ls, but I caught those really early on for some reason. I figured the lexical implementation just worked so didn't mention it, but we might want to crib those or at least take a look.

@katafrakt
Copy link
Contributor

Tested on Fish (MacOS, Mise) and seems to work fine.

@doorgan
Copy link
Collaborator

doorgan commented Jan 30, 2026

@mhanberg these are the ones NextLS gets rid of: ROOTDIR, BINDIR, RELEASE_ROOT, RELEASE_SYS_CONFIG
When I was testing this only RELEASE_ROOT was problematic. I had found the same vars as you did, but after trial and error I figured removing RELEASE_ROOT only was enough. I don't think it hurts to remove the other too though.

@mhanberg
Copy link
Member

We can just do release root if that's what your research indicates

@mhanberg
Copy link
Member

So can we actually just delete that env var or do we have to actually filter paths that have that root as a prefix?

@doorgan
Copy link
Collaborator

doorgan commented Jan 30, 2026

Sorry I misspoke, I was thinking of a different but related issue.

ROOTDIR, BINDIR, ERLEXEC_DIR, RELEASE_SYS_CONFIG and RELEASE_ROOT can be an issue if we keep them in the env we pass to the child node. What I had found was that(on windows) only ERLEXEC_DIR causes issues if not reset.

When finding the elixir executable though, the RELEASE_ROOT directory is included in the PATH used by :os.find_executable, so we need to filter it out to let the OS find the right executable.

So there's two related issues:

  • Some env vars included in releases cause issues if passed to the child node via Port.open (those are the env vars NextLS removed, and I narrowed it down to ERLECEX_DIR on windows, the rest don't seem to cause issues in my testing)
  • The RELEASE_ROOT is included in the PATH when we try to find the right elixir executable so we need to filter it. For plain releases that will point to the plain release; for burrito releases it will point to the elixir embedded by burrito

I haven't seen RELEASE_ROOT interfere with the child node if not removed, I think we can safely delete it, but I didn't find it harmful.

As a side note: in case we fail to find any elixir executable, the fallback_elixir function will call :os.find_executable with the RELEASE_ROOT in the path so we pick up the elixir embedded by burrito.

@mhanberg
Copy link
Member

So this is good to merge as is?

@doorgan
Copy link
Collaborator

doorgan commented Jan 30, 2026

Yes I think so, I just wanted to see if it was working in other environments too since this whole module is very finicky. It looks like it does.

@doorgan doorgan merged commit 375391c into elixir-lang:main Jan 30, 2026
37 of 38 checks passed
@mhanberg
Copy link
Member

❤️

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants