usestrix/strix · error · ValueError
'{path}' is not an existing directory.
Error message
'{path}' is not an existing directory. What it means
check_mountable_dir resolves the path and requires it to be an existing directory before the sandbox-mount safety checks. Unlike the is_dir() check in infer_target_type, this uses the RESOLVED path, so symlinks pointing at non-directories or paths removed between call and resolution fail here.
Source
Thrown at strix/interface/utils.py:1388
".docker",
".config",
".npm",
".pki",
".terraform.d",
}
)
def _is_within(path: Path, ancestor: Path) -> bool:
ancestor_parts = [part.casefold() for part in ancestor.parts]
path_parts = [part.casefold() for part in path.parts]
return path_parts[: len(ancestor_parts)] == ancestor_parts
def check_mountable_dir(path: Path) -> None:
resolved = path.resolve()
if not resolved.is_dir():
raise ValueError(f"'{path}' is not an existing directory.")
# Both the literal and the resolved form: macOS reaches /etc through the
# /private/etc symlink, and only the resolved path is compared below.
exact = {str(Path(root)).casefold() for root in _FORBIDDEN_MOUNT_ROOTS}
exact |= {str(Path(root).resolve()).casefold() for root in _FORBIDDEN_MOUNT_ROOTS}
exact.add(str(Path.home().resolve()).casefold())
tree_roots = set(_FORBIDDEN_MOUNT_TREES)
if os.name == "nt":
drive = Path(resolved.anchor)
tree_roots |= {str(drive / name) for name in _FORBIDDEN_WINDOWS_TREE_NAMES}
exact.add(str(drive / "Users").casefold())
trees = [Path(root) for root in tree_roots] + [Path(root).resolve() for root in tree_roots]
if (
str(resolved).casefold() in exact
or resolved.parent == resolved
or any(_is_within(resolved, tree) for tree in trees)
):
raise ValueError(View on GitHub (pinned to 8551339130)
Solutions
- Pass a directory that exists at call time: Path(target).resolve().is_dir() must be True.
- If using symlinked release dirs, point at a stable path or re-create the symlink before scanning.
- Target the project folder, not a file inside it.
Example fix
# before
check_mountable_dir(Path("./current")) # dangling symlink
# after
check_mountable_dir(Path("/srv/app/releases/2026-08-14").resolve()) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
resolved = Path(target).resolve()
if not resolved.is_dir():
raise SystemExit(f"{target} resolves to {resolved}, which is not an existing directory")
check_mountable_dir(resolved) Type guard
def is_existing_directory(path: str | Path) -> bool:
try:
return Path(path).resolve().is_dir()
except OSError:
return False Try / catch
try:
check_mountable_dir(Path(target))
except ValueError as e:
if "is not an existing directory" in str(e):
raise SystemExit(f"Scan target must be a live directory: {target}") from e
raise Prevention
- Resolve symlinks yourself before scanning so dangling links surface early
- Avoid symlink-of-the-day directories that can rotate away mid-pipeline
When it happens
Trigger: check_mountable_dir(Path('mylink')) where mylink resolves to a file or to a deleted path; a symlink chain where the final target no longer exists; calling the function directly with a file path.
Common situations: Passing a symlinked 'current' release directory whose target was rotated away; wrapper code re-validating a path after the directory was moved; passing a project file rather than its folder.
Related errors
- Refusing to mount '{resolved}' into the sandbox: it is a sys
- Refusing to mount '{resolved}' into the sandbox: '{credentia
- strix_image is not configured. Set it in ~/.strix/cli-config
- Path exists but is not a directory: {target}
- Target list file '{path_str}' is not an existing file.
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/f3e3e438c25389a9.
Report an issue: GitHub.