Skip to content

fix: guard os.getcwd() against deleted CWD (FileNotFoundError) - #4982

Open
lbruceolson wants to merge 1 commit into
NousResearch:mainfrom
lbruceolson:fix/safe-getcwd-deleted-cwd
Open

fix: guard os.getcwd() against deleted CWD (FileNotFoundError)#4982
lbruceolson wants to merge 1 commit into
NousResearch:mainfrom
lbruceolson:fix/safe-getcwd-deleted-cwd

Conversation

@lbruceolson

Copy link
Copy Markdown

What does this PR do?

Python's os.getcwd() raises FileNotFoundError when the shell's current working directory no longer exists on disk. This happens when a terminal (e.g. Warp) is open in a directory that gets deleted or renamed while the pane is still sitting in it. The result is hermes crashing before it can even display the banner.

This PR adds a _safe_getcwd() helper that wraps os.getcwd() in a try/except FileNotFoundError and falls back to the user's home directory (~). All six bare os.getcwd() call sites in cli.py are replaced with _safe_getcwd():

  • load_cli_config() — initial CWD resolution
    • HermesCLI.show_banner() — banner display
    • HermesCLI checkpoint command handler
    • HermesCLI._show_config()/config display
    • HermesCLI.run() tools-refresh path
    • preprocess_context_references() call — context file expansion

Related Issue

No existing issue. Discovered during normal use with the Warp terminal on Linux.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Reproducer

  1. Open a terminal pane in any directory (e.g. /tmp/test-dir)
    1. Delete that directory from another shell: rm -rf /tmp/test-dir
    1. Launch hermes from the original pane
    1. Without this fix: FileNotFoundError: [Errno 2] No such file or directory
    1. With this fix: hermes starts normally, CWD falls back to ~

Terminals like Warp aggressively track the CWD in each pane. If a
directory is deleted or renamed while a pane is sitting in it, the
shell's CWD pointer becomes stale. Python's os.getcwd() then raises
FileNotFoundError on the next launch, crashing hermes before it can
even show the banner.

Add a _safe_getcwd() helper that catches FileNotFoundError and falls
back to the user's home directory. Replace all six bare os.getcwd()
call sites in cli.py with _safe_getcwd():

- load_cli_config()         – initial CWD resolution
- HermesCLI.show_banner()   – banner display
- HermesCLI (checkpoint cmd) – checkpoint command handler
- HermesCLI._show_config()  – /config display
- HermesCLI.run() (refresh) – tools-refresh path
- preprocess_context_references() call – context file expansion
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #10233 — same os.getcwd() FileNotFoundError guard in CLI startup.

1 similar comment
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #10233 — same os.getcwd() FileNotFoundError guard in CLI startup.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for identifying a real deleted-CWD failure mode. The startup defect still exists on current main, but this patch needs current-tree salvage and broader launch-surface coverage.

Problems

  • cli.py:602 still calls os.getcwd() unconditionally for the local backend in load_cli_config(), before the classic CLI can render its banner.
  • The PR only changes cli.py; the TUI launcher independently calls os.getcwd() at hermes_cli/main.py:2037.
  • Current cli.py:2855 also uses os.getenv("TERMINAL_CWD", os.getcwd()); the default expression is evaluated eagerly, so a deleted CWD still raises even when TERMINAL_CWD is set.
  • The diff adds no regression test. Existing deleted-CWD tests cover only tools/terminal_tool.py (tests/tools/test_terminal_task_cwd.py:226-247).

Suggested changes

  • Port the guard to the current load_cli_config() branch at cli.py:593-605 and add a test that makes cli.os.getcwd() raise while invoking the real loader.
  • Cover the TUI launch path at hermes_cli/main.py:2037 and the remaining current CLI callers.

Automated hermes-sweeper review.

Comment thread cli.py

logger = logging.getLogger(__name__)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please extend this recovery to the TUI launcher as well: current hermes_cli/main.py:2037 independently calls os.getcwd() while setting HERMES_CWD, and this cli.py-only patch cannot protect that startup path.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants