agentscope-ai/agentscope · error · ValueError

{label} must be a real directory: {path}

Error message

{label} must be a real directory: {path}

What it means

_directory_identity requires every mount source to be a real directory (not a symlink, not a file). It raises ValueError with the offending label and path; __init__ and the pre-execution validator both call it, so the error surfaces either at construction or at first run.

Source

Thrown at src/agentscope/workspace/_bubblewrap/_bubblewrap_backend.py:507

            )
        except ValueError as exc:
            raise RuntimeError(
                "host_cache_dir was removed or replaced before execution.",
            ) from exc
        if identity != self._host_cache_identity:
            raise RuntimeError(
                "host_cache_dir was replaced before execution.",
            )

    @staticmethod
    def _directory_identity(
        path: str,
        *,
        label: str,
    ) -> tuple[int, int]:
        """Return a stable identity for a real directory mount source."""
        if os.path.islink(path) or not os.path.isdir(path):
            raise ValueError(f"{label} must be a real directory: {path}")
        stat_result = os.stat(path, follow_symlinks=False)
        return stat_result.st_dev, stat_result.st_ino

    @staticmethod
    def _paths_overlap(left: str, right: str) -> bool:
        """Return whether either real path contains the other."""
        left_real = os.path.realpath(left)
        right_real = os.path.realpath(right)
        try:
            common = os.path.commonpath([left_real, right_real])
        except ValueError:
            return False
        return common in (left_real, right_real)

    def _base_env(self) -> dict[str, str]:
        """Environment visible to sandboxed commands."""
        path_parts = [
            f"{SANDBOX_WORKDIR}/.agentscope/.venv/bin",

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Replace the symlink with a real directory (or bind mount) and pass the real path
  2. Create the directory first: os.makedirs(path, exist_ok=True)
  3. Verify with os.path.islink(path) == False and os.path.isdir(path) before constructing

Example fix

# before
ws = BubblewrapWorkspace(host_workdir='/data/link-to-ws')  # symlink
# after
os.makedirs('/data/ws', exist_ok=True)
ws = BubblewrapWorkspace(host_workdir='/data/ws')
Defensive patterns

Strategy: type-guard

Validate before calling

import os
for p in (workdir, tmpdir, cache_dir):
    if p is not None:
        assert not os.path.islink(p) and os.path.isdir(p), f'bad mount source: {p}'

Type guard

def is_real_dir(p: str) -> bool:
    return not os.path.islink(p) and os.path.isdir(p)

Try / catch

except ValueError as e:
    if 'must be a real directory' in str(e):
        os.makedirs(p, exist_ok=True)  # then retry construction

Prevention

When it happens

Trigger: Passing host_workdir/host_tmpdir/host_cache_dir that is a symlink to a directory, a regular file, or a nonexistent path.

Common situations: Symlinked workspace dirs (common in dotfile-managed setups or Docker volumes), typos in paths, or pointing at a path created later by another service.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/f704edf9b2e66717. Report an issue: GitHub.