agentscope-ai/agentscope · error · ValueError

host_cache_dir must not be a symbolic link.

Error message

host_cache_dir must not be a symbolic link.

What it means

The explicit host_cache_dir for a BubblewrapWorkspace must not be a symbolic link, because it is used directly as a Bubblewrap bind source and symlinks would escape or complicate the sandbox's path resolution. The check uses lexists+islink so it catches dangling and valid symlinks alike.

Source

Thrown at src/agentscope/workspace/_bubblewrap/_bubblewrap_workspace.py:255

                workdir.encode("utf-8"),
                digest_size=16,
            ).hexdigest()
            cache_root = os.path.join(
                os.path.dirname(workdir),
                ".agentscope-bwrap-cache",
            )
            self._ensure_cache_directory(
                cache_root,
                make_private=True,
            )
            path = os.path.join(
                cache_root,
                key,
            )
            make_private = True

        if os.path.lexists(path) and os.path.islink(path):
            raise ValueError("host_cache_dir must not be a symbolic link.")
        cache_dir = os.path.realpath(path)
        try:
            common = os.path.commonpath([workdir, cache_dir])
        except ValueError:
            common = ""
        if common in (workdir, cache_dir):
            raise ValueError(
                "host_cache_dir must not overlap host_workdir because it "
                "is used as a Bubblewrap bind source.",
            )

        self._ensure_cache_directory(
            path,
            make_private=make_private,
        )
        return os.path.realpath(path)

    @staticmethod

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Pass the realpath: host_cache_dir=os.path.realpath(p)
  2. Remove the symlink and use a real directory
  3. Mount the underlying target directly as host_cache_dir

Example fix

# before
ws = BubblewrapWorkspace(host_cache_dir="~/cache-link")
# after
import os
ws = BubblewrapWorkspace(host_cache_dir=os.path.realpath(os.path.expanduser("~/cache-link")))
Defensive patterns

Strategy: validation

Validate before calling

import os
if os.path.islink(os.path.expanduser(cache_dir)):
    cache_dir = os.path.realpath(os.path.expanduser(cache_dir))

Type guard

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

Try / catch

try:
    ws = await BubblewrapWorkspace.create(host_cache_dir=p)
except ValueError as e:
    if "symbolic link" in str(e):
        p = os.path.realpath(p); retry

Prevention

When it happens

Trigger: Passing host_cache_dir that is (or contains as its final component) a symlink, e.g. /var/cache/myapp where myapp -> /mnt/cache; common on systems where /var/cache or tmpdirs are symlinked.

Common situations: macOS/Linux systems with symlinked cache dirs (e.g. nix, /tmp -> /private/tmp), CI setups linking cache directories, developers trying to share a cache via a link.

Related errors


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