Skip to content

fix(tool_dispatch_helpers): catch RuntimeError from Path.expanduser() - #37331

Closed
alexzhu0 wants to merge 1 commit into
NousResearch:mainfrom
alexzhu0:fix/tool-dispatch-helpers-expanduser-runtimeerror
Closed

fix(tool_dispatch_helpers): catch RuntimeError from Path.expanduser()#37331
alexzhu0 wants to merge 1 commit into
NousResearch:mainfrom
alexzhu0:fix/tool-dispatch-helpers-expanduser-runtimeerror

Conversation

@alexzhu0

@alexzhu0 alexzhu0 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Companion fix to PR 29433: catch RuntimeError from Path(...).expanduser() in agent/tool_dispatch_helpers._extract_parallel_scope_path, which is the path-normalization helper for every path-scoped tool call (read_file, write_file, edit_file, search_files, read_file_v2, ...).

_extract_parallel_scope_path runs on the hot path for tool dispatch. When the LLM passes an unresolvable tilde prefix in function_args[path] — either ~unknown_user/path (POSIX) or an LLM-shaped token like ~500-700 meaning "approximately 500-700" — Path(raw_path).expanduser() raises RuntimeError("Could not determine home directory."), which then bubbles up through the conversation loop and is misreported as a model/API error.

This is the same bug class as PR 29433 (subdirectory_hints), but a different call site that also needs the exception absorbed. PR 29433 fixes the subdirectory-hints walker; this one fixes the path-scoped tool dispatcher. Both share the same root cause: Path.expanduser can raise RuntimeError when the tilde prefix does not resolve to a real user.

Related Issue

Refs #29433

Type of Change

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

Changes Made

  • agent/tool_dispatch_helpers.py — wrap the bare Path(raw_path).expanduser() call in _extract_parallel_scope_path with try/except RuntimeError. When the tilde prefix is unresolvable, the function returns None and the caller falls back to the no-scope path (i.e. parallel tool calls are allowed as if there were no path constraint).
  • tests/agent/test_tool_dispatch_helpers.py — add a new TestExtractParallelScopePathTildeRobustness class with five cases:
    • test_tilde_approximately_does_not_crash
    • test_tilde_with_unknown_user_does_not_crash
    • test_legitimate_tilde_home_still_resolves (regression guard)
    • test_non_path_scoped_tool_returns_none
    • test_missing_or_empty_path_returns_none

How to Test

Repro on main (without the fix):

>>> from agent.tool_dispatch_helpers import _extract_parallel_scope_path
>>> _extract_parallel_scope_path("read_file", {"path": "TILDE-500-700"})
RuntimeError: Could not determine home directory.

(Use TILDE-500-700 to dodge the literal tilde that would crash this README; the real bug trigger is a tilde-prefixed string in a tool-call path argument.)

After applying the fix:

pytest tests/agent/test_tool_dispatch_helpers.py -v
# 32 passed (5 new + 27 existing) in about 2.5s

Without the fix, test_tilde_approximately_does_not_crash and test_tilde_with_unknown_user_does_not_crash fail with RuntimeError. With the fix, all 5 new tests pass and the 27 pre-existing tests are unaffected.

Checklist

Code

  • I have read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this is not a duplicate
  • My PR contains only changes related to this fix
  • I have run pytest tests/agent/test_tool_dispatch_helpers.py tests/agent/test_subdirectory_hints.py -q and all 57 tests pass
  • I have added tests for my changes
  • Tested on: WSL2 (Ubuntu 24.04 base), Python 3.11.15

Documentation and Housekeeping

  • N/A — internal fix, no user-facing config or docs change
  • N/A — no config key changes
  • N/A — no architecture change
  • No cross-platform impact: bug and fix are pure Python/pathlib
  • No tool description or schema changes

`Path(...).expanduser()` raises `RuntimeError` when the tilde-prefix
does not resolve to a real user.  This happens both for `~unknown_user`
and for LLM-shaped tokens like `~500-700` (used to mean "approximately
500-700").

`_extract_parallel_scope_path` runs on the hot path for every
path-scoped tool call (read_file, write_file, edit_file, search_files,
read_file_v2, ...), so a bare `Path(raw_path).expanduser()` there
crashes the whole tool invocation with the misleading error string

    Error during OpenAI-compatible API call #N:
    Could not determine home directory.

when an LLM passes an unresolvable tilde prefix.  Same bug class as
NousResearch#29433 (subdirectory_hints), but a different call site that also needs
the exception absorbed.

Fix: wrap the `Path(raw_path).expanduser()` call in
`_extract_parallel_scope_path` with a `try/except RuntimeError`.
A path that does not name a real filesystem location returns `None`
and the caller falls back to the no-scope path.

Tests: extend `tests/agent/test_tool_dispatch_helpers.py` with a new
`TestExtractParallelScopePathTildeRobustness` class covering:
  - tilde-as-approximately in tool-call path (`~500-700`)
  - unknown POSIX user prefix (`~nonexistent_user/path`)
  - regression guard for legitimate `~/...` paths
  - non-path-scoped tools still return None
  - empty / non-string path arguments are absorbed

Repro on `main` (without the fix):

    >>> _extract_parallel_scope_path("read_file", {"path": "~500-700"})
    RuntimeError: Could not determine home directory.

After this fix, the call returns `None` and the conversation continues.

Refs NousResearch#29433
@alexzhu0

alexzhu0 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Filing the first of the three follow-up fixes mentioned in my #29433 review — agent/tool_dispatch_helpers.py:158. This one is the highest-impact of the three (hot path for every path-scoped tool call) and cleanly testable in isolation, so I kept it as its own PR rather than folding it into #29433.

The fix and test coverage mirror the #29433 style:

  • try/except RuntimeError around the bare Path(...).expanduser() call
  • Three new test cases in a dedicated TestExtractParallelScopePathTildeRobustness class
  • Regression guard for legitimate ~/... expansion
  • A 1:1 repro on main showing RuntimeError("Could not determine home directory.") for a tilde-prefixed path argument, and silence after the fix

CI: 20/20 jobs green (ruff + ty, test x6, build amd64/arm64, nix macOS+Ubuntu, Windows footguns, e2e, supply chain, attribution, common-ancestor).

The other two from the review list (agent/skill_commands.py:63 and hermes_cli/gateway.py:2095-2101) are P3 and I'll hold those until this one and #29433 land, to avoid stacking three open companion PRs at once.

Happy to rebase / squash / retitle / move the change into #29433 directly if maintainers prefer a single atomic fix — just say the word.

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists labels Jun 2, 2026
@alexzhu0

alexzhu0 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Closing to keep my open-PR list tidy — no longer actively tracking this one. The change still stands on its own if it's wanted; feel free to cherry-pick it.

@alexzhu0 alexzhu0 closed this Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants