Skip to content

[BUG]: vfox env serves the cached output after a cd: a .nvmrc / .node-version is ignored on the way in and kept on the way out #745

Closed

Description

@linghengqian

Version
vfox 1.0.13 (release binary) and main at cdf0747 (2026-11-02, RuntimeVersion is still 1.0.13), with the nodejs plugin 0.5.3 from the registry. The two builds print the same lines in everything below.

OS
Linux (Ubuntu 26.04.1 on WSL2), bash 5.3.9, in a scratch HOME started with env -i. I ran only bash on Linux and only the nodejs plugin. The code involved depends on neither the shell nor the OS, and other plugins that declare legacyFilenames go through the same ParseLegacyFile call, so I expect the same elsewhere, but I have not tried.

Describe the bug
A legacy version file such as .nvmrc or .node-version takes effect when a shell starts in its directory, but not when you cd into that directory from a running shell. And a shell that started in such a directory stays on the file's version when you cd out of it, instead of going back to the global one. A .vfox.toml has neither problem.

At every prompt in such a directory vfox env still calls the plugin's ParseLegacyFile, so vfox does learn what the file says (Found nodejs@18.20.8 below). That answer is not what decides whether the cached output can be reused, so vfox prints the output it cached for the previous directory.

Steps to reproduce
legacyVersionFile.enable is true and legacyVersionFile.strategy is specified, the defaults.

$ vfox add nodejs
$ vfox install nodejs@18.20.8
$ vfox install nodejs@26.13.0
$ vfox use -g nodejs@26.13.0
$ mkdir -p ~/demo/plain ~/demo/with-nvmrc ~/demo/with-toml
$ printf '18.20.8\n' > ~/demo/with-nvmrc/.nvmrc
$ printf '[tools]\nnodejs = "18.20.8"\n' > ~/demo/with-toml/.vfox.toml

Going in: a bash that starts in plain, then cds into the directory with the .nvmrc. The directory with the .vfox.toml switches right away, for comparison:

$ cd ~/demo/plain
$ eval "$(vfox activate bash)"
$ node -v
v26.13.0
$ cd ../with-nvmrc
$ cat .nvmrc
18.20.8
$ node -v
v26.13.0
$ vfox --debug env -s bash 2>&1 | grep -o -E "Parsing legacy file [^ ]+|Found nodejs@[0-9.]+|Config changed: [a-z]+|Using cached output"
Parsing legacy file /home/me/demo/with-nvmrc/.nvmrc
Found nodejs@18.20.8
Config changed: false
Using cached output
$ cd ../with-toml
$ cat .vfox.toml
[tools]
nodejs = "18.20.8"
$ node -v
v18.20.8

Going out: a bash that starts in the directory with the .nvmrc, then cds to plain:

$ cd ~/demo/with-nvmrc
$ eval "$(vfox activate bash)"
$ node -v
v18.20.8
$ cd ../plain
$ node -v
v18.20.8
$ vfox --debug env -s bash 2>&1 | grep -o -E "Parsing legacy file [^ ]+|Found nodejs@[0-9.]+|Config changed: [a-z]+|Using cached output"
Config changed: false
Using cached output

Root cause
envFlag (cmd/commands/env.go#L147-L197) decides whether it can reuse the output it cached for this shell:

  • It first calls loadToolChain (cmd/commands/tool_resolution.go#L31-L52), which reads the config files and calls ParseLegacyFile for the current directory. A legacy result only goes into the in-memory project config.
  • configPaths then lists only the vfox config files that exist (L154-L164). A directory with only a .nvmrc has no project config file, so the project entry is empty on both sides of the cd.
  • ConfigState.HasChanged (internal/env/state.go#L112-L164) compares that project path with the last one, PATH with the cached PATH, and the modification time of each tracked file with the stored one. In the transcripts none of the three differs (Config changed: false), and envFlag prints the cached output (L189-L197).

So the version file, and the directory it is read from, are inputs of the output that the cache does not know about. AGENTS.md already states the principle for path.mode: the cached output is keyed by the PATH policy "because config.yaml is not among the files whose modification time is tracked; a setting that changes the PATH order has to be part of that key" (L113), and it says that loadToolChain "reads the version files, legacy ones included, for env, activate and doctor" (L90).

Expected behavior
After cd ../with-nvmrc, node -v prints v18.20.8, and after cd ../plain from there it prints v26.13.0 again, as the directory with the .vfox.toml does.

Possible fix
env runs at every prompt (AGENTS.md), so both ideas below are comparisons of values that envFlag already has:

  1. Keep the working directory in the state, the way CachedPathPolicy keeps the PATH policy, and count a different directory as a change. I tried this on v1.0.13: 55 added lines with a test (ConfigState.DirChanged and SetDir, used in envFlag). A shell that went into a .nvmrc directory, a .node-version directory, a plain directory, two .vfox.toml directories and a plain directory again came out right at every step, going out included, also with plugin 0.5.3. It does not notice an edit of the version file in the directory the shell is already in.
  2. Keep what loadToolChain resolved (the tool and version pairs, legacy ones included) and count a different set as a change. envFlag has it before the cache check, so it needs no list of files per plugin, and it should also catch an edit in place. I have not tried this one.

Activity

  1. thelastbackspace commented on Nov 5, 2026

    @thelastbackspace
    Contributor

    I'd like to take this one. I'm going with your second idea: store the tools the project scope resolved to (legacy ones included) in the env state next to the path policy, and treat a different set as a change. That also covers editing the .nvmrc in place, which the directory-only check misses. I have it working with a regression test on the existing env command fixture.

  2. added this to the 1.0.14 milestone on Nov 5, 2026
  3. added 2 commits that reference this issue on Nov 6, 2026
    37cff8f
    85f35ec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions