HKUDS/Vibe-Trading · error · ValueError

run_dir is required to write/edit {file_path!r}, or the path

Error message

run_dir is required to write/edit {file_path!r}, or the path must resolve inside allowed {purpose} roots.

What it means

When no run_dir is supplied, resolve_safe_path requires the file_path to resolve inside one of the allowed roots for that purpose; otherwise this error explains that run_dir is required for write/edit operations outside allowlisted roots.

Source

Thrown at agent/src/tools/path_utils.py:238

        try:
            return safe_path(file_path, run_root)
        except ValueError as exc:
            # Fallback to allowed roots if safe_path containment fails
            candidate = Path(file_path).expanduser().resolve()
            for root in allowed_roots:
                if candidate.is_relative_to(root):
                    return candidate
            raise ValueError(
                f"Path {file_path!r} escapes run_dir {run_dir!r} and is not in allowed {purpose} roots."
            ) from exc

    # If no run_dir, path must resolve inside one of the allowed roots
    candidate = Path(file_path).expanduser().resolve()
    for root in allowed_roots:
        if candidate.is_relative_to(root):
            return candidate

    raise ValueError(
        f"run_dir is required to write/edit {file_path!r}, or the path must resolve inside allowed {purpose} roots."
    )


def _allowed_run_roots() -> list[Path]:
    """Return all roots allowed for run_dir-based tools."""
    raw = get_env_config().api.vibe_trading_allowed_run_roots
    configured: list[Path] = []
    for item in raw.split(","):
        item = item.strip()
        if not item:
            continue
        _rejects_unc(item)
        configured.append(Path(item).expanduser().resolve())

    roots: list[Path] = []
    for root in [*_default_run_roots(), *configured]:
        resolved = root.resolve()

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Create/obtain a run_dir and pass it to the tool
  2. Or restrict writes to a directory listed in allowed write roots
  3. Verify the path with expanduser().resolve() matches an allowed root exactly (no symlinks)

Example fix

# before
tool.execute(file_path="/home/user/note.md", mode="edit")
# after
run = create_run_dir()  # under allowed run roots
tool.execute(file_path=str(run / "note.md"), run_dir=str(run), mode="edit")
Defensive patterns

Strategy: validation

Validate before calling

if run_dir is None:
    cand = Path(file_path).expanduser().resolve()
    assert any(cand.is_relative_to(r) for r in allowed_write_roots()), "need run_dir or allowed root"

Type guard

def can_write_without_run_dir(p: str, roots: list[Path]) -> bool:
    c = Path(p).expanduser().resolve()
    return any(c.is_relative_to(r) for r in roots)

Try / catch

try:
    target = resolve_safe_path(file_path, None, purpose="write")
except ValueError as e:
    if "run_dir is required" in str(e):
        run_dir = create_run_dir(); target = resolve_safe_path(str(run_dir / Path(file_path).name), str(run_dir), purpose="write")

Prevention

When it happens

Trigger: Calling a write/edit tool without run_dir and with a path outside all allowed roots.

Common situations: Ad-hoc scripts invoking file tools directly without creating a run directory, or expecting cwd to be implicitly allowed.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/a2432c272d5754e9. Report an issue: GitHub.