From 34f1e9b089f82d5fa72143fca33477748e5c0a2a Mon Sep 17 00:00:00 2001 From: danielhanchen Date: Wed, 29 Jul 2026 09:25:37 +0000 Subject: [PATCH] Keep the managed Node on PATH when the home directory is unavailable _augment_path_with_install_dirs returned as soon as Path.home() raised, and the managed Node lookup sits after that return, so a container running under a bare UID never got the managed Node on PATH. An npm agent shim installed there still resolved, then failed because `env node` could not find a node. The same environment is the one the install hint was already taught to handle. Only the user install dirs need a home, so a missing one now leaves them out rather than skipping the rest. When there is nothing to add, PATH is still left untouched, as before. unsloth_cli/tests/test_start.py: 390 passed. --- unsloth_cli/commands/start.py | 6 ++++-- unsloth_cli/tests/test_start.py | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/unsloth_cli/commands/start.py b/unsloth_cli/commands/start.py index de42c4d27d..1220503dc9 100644 --- a/unsloth_cli/commands/start.py +++ b/unsloth_cli/commands/start.py @@ -2449,11 +2449,13 @@ def _augment_path_with_install_dirs() -> None: # Add known install dirs to PATH so a freshly installed agent resolves without a new # shell. User agent dirs are appended so existing tools keep precedence. A managed Node # selected over the system runtime is prepended so Node-backed shims use that same runtime. + # Only the user install dirs need a home; a missing one must not also drop the managed + # Node, or a shim resolved here fails on `env node` under a bare container UID. try: home = Path.home() except (RuntimeError, OSError): - return - candidates = [home / ".local" / "bin"] + home = None + candidates = [home / ".local" / "bin"] if home is not None else [] if os.name == "nt": appdata = os.environ.get("APPDATA") if appdata: diff --git a/unsloth_cli/tests/test_start.py b/unsloth_cli/tests/test_start.py index f9106b4ab3..63a79e853c 100644 --- a/unsloth_cli/tests/test_start.py +++ b/unsloth_cli/tests/test_start.py @@ -5237,6 +5237,42 @@ def test_session_config_falls_back_when_existing_temp_root_is_unwritable(monkeyp assert not home.exists() +def test_augment_path_keeps_managed_node_without_a_home(monkeypatch, tmp_path): + # A bare container UID has no home, but the managed Node is still the runtime that + # resolves a Node-backed shim, so it must stay on PATH. + managed_bin = tmp_path / "node" / "bin" + managed_bin.mkdir(parents = True) + monkeypatch.setattr( + start, + "_managed_node_tools", + lambda: (managed_bin / "node", managed_bin / "npm", True), + ) + monkeypatch.setattr( + start.Path, + "home", + staticmethod(lambda: (_ for _ in ()).throw(RuntimeError("no home directory"))), + ) + monkeypatch.setenv("PATH", "/usr/bin") + + start._augment_path_with_install_dirs() + + assert os.environ["PATH"].split(os.pathsep)[0] == str(managed_bin) + + +def test_augment_path_leaves_path_alone_when_nothing_to_add(monkeypatch): + monkeypatch.setattr(start, "_managed_node_tools", lambda: None) + monkeypatch.setattr( + start.Path, + "home", + staticmethod(lambda: (_ for _ in ()).throw(RuntimeError("no home directory"))), + ) + monkeypatch.setenv("PATH", "/usr/bin") + + start._augment_path_with_install_dirs() + + assert os.environ["PATH"] == "/usr/bin" + + def test_probe_env_carries_install_dirs_and_restores_path(monkeypatch, tmp_path): # A shim resolved via Studio's managed Node needs that node on PATH when it runs. managed_bin = tmp_path / "node" / "bin"