Skip to content

terminal: Skip SHLVL when loading login shell environment#46273

Merged
Veykril merged 1 commit intozed-industries:mainfrom
edlsh:fix/shlvl-process-env
Jan 8, 2026
Merged

terminal: Skip SHLVL when loading login shell environment#46273
Veykril merged 1 commit intozed-industries:mainfrom
edlsh:fix/shlvl-process-env

Conversation

@edlsh
Copy link
Contributor

@edlsh edlsh commented Jan 7, 2026

Fixes #33958

Problem

PR #44835 attempted to fix SHLVL starting at 2 by removing it from the env HashMap passed to alacritty. However, that HashMap is only an overlay — alacritty uses the parent process environment as a base and applies the overlay on top. Since alacritty never calls env_remove("SHLVL"), the terminal shell still inherits SHLVL from Zed's process environment.

Root Cause

The real issue is in load_login_shell_environment():

  1. shell_env::capture() spawns a login shell to capture environment variables
  2. That login shell increments SHLVL (from 0→1 or n→n+1)
  3. The captured env (including the incremented SHLVL) is written to Zed's process environment via env::set_var
  4. When you open a terminal, the shell inherits Zed's SHLVL and increments it again → starts at 2
  5. On reload, shell_env::capture() runs again with the already-elevated SHLVL, incrementing it further → +2 per reload

Fix

Skip SHLVL when setting Zed's process environment in load_login_shell_environment(). This prevents the login-shell capture from polluting Zed's env, so terminals start fresh with the correct SHLVL.

Fixes #33958

PR #44835 attempted to fix SHLVL starting at 2 by removing it from the
env HashMap passed to alacritty. However, that HashMap is only an overlay -
alacritty uses the parent process environment as a base and applies the
overlay on top. Since alacritty never calls env_remove("SHLVL"), the
terminal shell still inherits SHLVL from Zed's process environment.

The root cause is that load_login_shell_environment() captures env vars
from a login shell (which increments SHLVL) and writes them to Zed's
process environment. When a terminal is opened, the shell inherits this
already-incremented SHLVL and increments it again.

This fix skips SHLVL when setting Zed's process environment, preventing
the login-shell capture from polluting it. Terminals now start with the
correct SHLVL.
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Jan 7, 2026
Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

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

Thanks!

@Veykril Veykril enabled auto-merge (squash) January 8, 2026 09:52
@zed-industries-bot
Copy link
Contributor

Warnings
⚠️

This PR is missing release notes.

Please add a "Release Notes" section that describes the change:

Release Notes:

- Added/Fixed/Improved ...

If your change is not user-facing, you can use "N/A" for the entry:

Release Notes:

- N/A

Generated by 🚫 dangerJS against 4e4dd72

@Veykril Veykril merged commit 466c700 into zed-industries:main Jan 8, 2026
24 checks passed
baldwindavid added a commit to baldwindavid/zed that referenced this pull request Jan 8, 2026
* main: (349 commits)
  component_preview: Fix license symlink (zed-industries#46379)
  Do not react on already observed buffer edits' versions (zed-industries#46308)
  Fix EP CLI output flicker (zed-industries#46313)
  vim: Fix bug where repeat operator could lead to unrecoverable replaying state (zed-industries#46376)
  vim: Implement text-based matching bracket logic for Vim '%' motion to correctly find pairs within comments (zed-industries#45559)
  Improve LSP button error message (zed-industries#46377)
  agent: Make reject/accept keybindings consistent with restore/stage (zed-industries#46373)
  Enable test-support features for some dev dependencies (zed-industries#46370)
  Capture terminal output when thread is interrupted (zed-industries#46306)
  Inline assistant tools: no more feature flag (zed-industries#46107)
  Add `ep split` subcommand for dataset splitting (zed-industries#46364)
  lsp_button: Fix long LSP version label (zed-industries#46359)
  remote: Introduce a proper mock remote connection (zed-industries#46337)
  ep: Allow matching patches against files without trailing newlines (zed-industries#46357)
  docs: Update "Custom Keybindings for Extension-Based Agents section" to include a troubleshooting note for defining an agent name (zed-industries#46144)
  Fail early if clangd is downloaded on aarch Linux (zed-industries#46346)
  ep: Handle errored requests in Anthropic batches (zed-industries#46351)
  settings_ui: Fix settings search missing results when BM25 finds partial matches (zed-industries#46349)
  workspace: Unpreview active tab when closing other tabs (zed-industries#46294)
  terminal: Skip SHLVL when loading login shell environment (zed-industries#46273)
  ...
rtfeldman pushed a commit that referenced this pull request Jan 9, 2026
Fixes #33958

## Problem

PR #44835 attempted to fix SHLVL starting at 2 by removing it from the
`env` HashMap passed to alacritty. However, that HashMap is only an
**overlay** — alacritty uses the parent process environment as a base
and applies the overlay on top. Since alacritty never calls
`env_remove("SHLVL")`, the terminal shell still inherits `SHLVL` from
Zed's process environment.

## Root Cause

The real issue is in `load_login_shell_environment()`:

1. `shell_env::capture()` spawns a login shell to capture environment
variables
2. That login shell increments `SHLVL` (from 0→1 or n→n+1)
3. The captured env (including the incremented `SHLVL`) is written to
Zed's **process environment** via `env::set_var`
4. When you open a terminal, the shell inherits Zed's `SHLVL` and
increments it again → starts at 2
5. On reload, `shell_env::capture()` runs again with the
already-elevated `SHLVL`, incrementing it further → +2 per reload

## Fix

Skip `SHLVL` when setting Zed's process environment in
`load_login_shell_environment()`. This prevents the login-shell capture
from polluting Zed's env, so terminals start fresh with the correct
`SHLVL`.
@shinebayar-g
Copy link

shinebayar-g commented Jan 15, 2026

Terminal: Fixed a bug where the integrated terminal's SHLVL (shell nesting level) started at 2 and increased on each workspace reload. (#46273)

I was reading through the change log and noticed that this bug still exists?

version

Zed Preview 0.220.0 
3f8d007c5319fbdbd2fcd420f5b2102d27a4ba76

0.220.0+preview.120.3f8d007c5319fbdbd2fcd420f5b2102d27a4ba76

log

# in native terminalecho $SHLVL
1
# open zed
❯ zed .
# inside zed, opened a new terminalecho $SHLVL
2
# cmd+shift+p: run "workspace: reload" command
# run it again, it's ever increasing.echo $SHLVL
3

nvm it seems people already reported this in #33958 (comment)

LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ries#46273)

Fixes zed-industries#33958

## Problem

PR zed-industries#44835 attempted to fix SHLVL starting at 2 by removing it from the
`env` HashMap passed to alacritty. However, that HashMap is only an
**overlay** — alacritty uses the parent process environment as a base
and applies the overlay on top. Since alacritty never calls
`env_remove("SHLVL")`, the terminal shell still inherits `SHLVL` from
Zed's process environment.

## Root Cause

The real issue is in `load_login_shell_environment()`:

1. `shell_env::capture()` spawns a login shell to capture environment
variables
2. That login shell increments `SHLVL` (from 0→1 or n→n+1)
3. The captured env (including the incremented `SHLVL`) is written to
Zed's **process environment** via `env::set_var`
4. When you open a terminal, the shell inherits Zed's `SHLVL` and
increments it again → starts at 2
5. On reload, `shell_env::capture()` runs again with the
already-elevated `SHLVL`, incrementing it further → +2 per reload

## Fix

Skip `SHLVL` when setting Zed's process environment in
`load_login_shell_environment()`. This prevents the login-shell capture
from polluting Zed's env, so terminals start fresh with the correct
`SHLVL`.
LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ries#46273)

Fixes zed-industries#33958

## Problem

PR zed-industries#44835 attempted to fix SHLVL starting at 2 by removing it from the
`env` HashMap passed to alacritty. However, that HashMap is only an
**overlay** — alacritty uses the parent process environment as a base
and applies the overlay on top. Since alacritty never calls
`env_remove("SHLVL")`, the terminal shell still inherits `SHLVL` from
Zed's process environment.

## Root Cause

The real issue is in `load_login_shell_environment()`:

1. `shell_env::capture()` spawns a login shell to capture environment
variables
2. That login shell increments `SHLVL` (from 0→1 or n→n+1)
3. The captured env (including the incremented `SHLVL`) is written to
Zed's **process environment** via `env::set_var`
4. When you open a terminal, the shell inherits Zed's `SHLVL` and
increments it again → starts at 2
5. On reload, `shell_env::capture()` runs again with the
already-elevated `SHLVL`, incrementing it further → +2 per reload

## Fix

Skip `SHLVL` when setting Zed's process environment in
`load_login_shell_environment()`. This prevents the login-shell capture
from polluting Zed's env, so terminals start fresh with the correct
`SHLVL`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

$SHLVL starts at 2 and increases by 2 every time Zed is reloaded

4 participants