A project's .ruby-version pins 4.0.7 under rbenv, yet a newly opened terminal runs the system Ruby there; how do you diagnose and fix it?
answer
- is the shims dir first
- type -a ruby shows the order
- login vs non-login startup files
- stray RBENV_VERSION outranks the file
- rbenv version names the origin
basics
~20 sCheck that ~/.rbenv/shims comes first on PATH with type -a ruby; usually the rbenv init line sits in a startup file that shell never reads, or a later PATH edit wins. Then run rbenv version to spot a stray RBENV_VERSION.
solid answer
~40 sI split it into two checks. First, is rbenv reached at all: `type -a ruby` must list `~/.rbenv/shims/ruby` first. If the shims directory is missing, the shell never evaluated `rbenv init -`; with rbenv 1.3.2, `rbenv init` typically writes that line to `~/.zprofile` for zsh or `~/.bash_profile` for bash, which non-login shells skip, so I move it to the file this terminal reads. If shims are present but not first, a later PATH edit put another Ruby ahead. Second, what does rbenv resolve: `rbenv version` names the source, and an inherited `RBENV_VERSION` beats `.ruby-version`, so I unset it. In CI the same bug appears because non-interactive shells read no profile; there I use `rbenv exec` or `eval "$(rbenv init - bash)"`.
code
bash · 10 linescd ~/code/billing-worker
type -a ruby # /usr/bin/ruby first -> shims not first on PATH
echo "$PATH" | tr ':' '\n' | grep -n rbenv
grep -n 'rbenv init' ~/.zprofile ~/.zshrc ~/.bashrc ~/.bash_profile 2>/dev/null
rbenv version # 3.4.7 (set by RBENV_VERSION environment variable)?
env | grep RBENV_VERSION
# fix: load rbenv in the file this shell reads, drop the stray export
echo 'eval "$(rbenv init - --no-rehash zsh)"' >> ~/.zshrc
exec zsh
type -a ruby # ~/.rbenv/shims/ruby firstgo deeper
Recall that rbenv only works when its shims directory is first on PATH, and that rbenv version tells you which setting chose the Ruby.
Explain which startup file rbenv init writes to, why login and non-login shells differ, and how RBENV_VERSION outranks .ruby-version.
Run the two-step diagnosis quickly: PATH order with type -a, then the origin from rbenv version, and fix CI with rbenv exec or an explicit init eval.
Standardise how developer machines and CI load the version manager so environment drift shows up as a clear failure, not a silently different Ruby.
## Two separate questions When a project pinned with `.ruby-version` runs the wrong Ruby in a fresh terminal, split the problem in two: 1. **Is rbenv even reached?** If `~/.rbenv/shims` is not first on `PATH`, the shell runs some other `ruby` and rbenv never sees the call. No rbenv setting can fix this. 2. **If it is reached, what does it resolve?** rbenv may be working perfectly and picking a different source than the file you expect. It is often the first kind, and the "new terminal" detail is the clue: an old terminal works, a new one does not, so something in shell startup differs. ## Step 1: is the shim reached? 1. `type -a ruby` (or `which -a ruby`) lists every `ruby` on `PATH` in order. The first line must be `~/.rbenv/shims/ruby`. 2. `echo "$PATH" | tr ':' '\n'` shows whether the shims directory is present at all, and what comes before it. 3. `command -v rbenv` confirms the `rbenv` command itself is reachable. If the shims directory is **missing**, the shell never evaluated `rbenv init -`. If it is **present but not first**, something prepended another Ruby after rbenv's line ran. ## Why a new terminal skips rbenv Since rbenv 1.3.0, running `rbenv init` with no arguments writes an `eval "$(rbenv init - --no-rehash <shell>)"` line into a startup file for you. Which file it picks decides which shells load rbenv: | Shell | File `rbenv init` 1.3.2 writes to | |---|---| | zsh | `~/.zprofile`, unless `~/.zshrc` already mentions rbenv | | bash | `~/.bashrc` if it exists and `~/.bash_profile` does not; otherwise the first of `~/.bash_profile`, `~/.bash_login`, `~/.profile` | | fish | `~/.config/fish/config.fish` | | ksh | `~/.profile` | Common failure patterns: - **Login vs non-login shells.** `~/.zprofile` and `~/.bash_profile` are read by login shells only. A terminal emulator, editor or multiplexer that starts a non-login interactive shell reads `~/.zshrc` or `~/.bashrc` instead, and never evaluates the rbenv line. - **A later PATH edit.** A line after the eval, or a file read after it, prepends another Ruby's `bin` directory (a package manager's Ruby, a language toolchain installer), so that Ruby wins. - **Testing in the old terminal.** Editing a startup file and re-checking in the same window proves nothing; only a fresh window runs startup the way the next terminal will. - **A shell that cached a path.** The shell's command hash can remember `/usr/bin/ruby` from before; `hash -r` clears it, and rbenv's integrated `rbenv rehash` runs it too. ## Step 2: what does rbenv resolve? Run `rbenv version`. The origin text names the culprit: - `(set by RBENV_VERSION environment variable)`: something exported the variable, and it outranks `.ruby-version`. Typical sources are an `export RBENV_VERSION=...` line in a dotfile, an `rbenv shell` run in a parent shell whose environment the new terminal inherited, or a terminal started by a process that ran under `rbenv exec`, which exports `RBENV_VERSION`. - `(set by ~/.rbenv/version)`: rbenv did not find the project's file. Check that it is non-empty, that you are inside the project tree, and that its first word is the version name. - A "version 4.0.7 is not installed" error naming the `.ruby-version` path: the file is read but the version is missing; run `rbenv install` in the project (it installs what `.ruby-version` names). ## Fixes - Move or copy the eval line into the file your terminal's shell actually reads, then open a new terminal to test. - Make sure the rbenv line comes **after** any other PATH edits that add a Ruby, or remove those edits. - Remove stray `RBENV_VERSION` exports; use `rbenv shell --unset` in a live shell. - Re-check with `type -a ruby` and `rbenv version` rather than trusting `ruby -v` alone. ## The same failure in CI and scripts CI steps and cron jobs usually run a **non-interactive** shell that reads neither profile file, so shims are never on `PATH` and the image's system Ruby runs. Reliable options: - Evaluate `eval "$(rbenv init - bash)"` at the start of the step. - Prepend `"$(rbenv root)/shims"` to `PATH` explicitly. - Call commands through `rbenv exec`, which resolves the version without any shell integration. - Install with `rbenv install -s` (no version argument) so a cached runner builds the pinned Ruby once and skips it afterwards.
- In a CI job, the tests run under the image's system Ruby although rbenv and the pinned version are installed; why, and what fixes it?The job's steps run in a non-interactive shell that reads no profile file, so `rbenv init -` never runs and the shims are not on `PATH`. Fix it inside the job: evaluate `eval "$(rbenv init - bash)"` first, prepend `$(rbenv root)/shims` to `PATH`, or run commands through `rbenv exec`. Pair it with `rbenv install -s` so a cached runner installs the pinned Ruby only once.
- rbenv version in the new terminal prints 3.4.7 (set by RBENV_VERSION environment variable); where can that come from?Something put `RBENV_VERSION` into the environment before the shell started: an `export` in a dotfile, an `rbenv shell` in a parent shell that launched this terminal or multiplexer, or a parent process started through `rbenv exec`, which exports the resolved `RBENV_VERSION`. Remove the source; `rbenv shell --unset` clears it in the live shell.
saying these in an interview costs you the question
- rbenv rehash puts a missing shims directory back on PATH
- Placing the rbenv init line anywhere in a profile guarantees rbenv wins PATH
- rbenv only reads .ruby-version when you cd into the directory
- Exporting RBENV_VERSION in the profile is a good way to pin one project
- Reinstalling Ruby 4.0.7 fixes a .ruby-version the terminal ignores