langchain-ai/deepagents · error · ValueError

workspace.{field} is not a directory: {value}

Error message

workspace.{field} is not a directory: {value}

What it means

Raised when the workspace path exists and resolves successfully but is not a directory (e.g. it is a file, socket, or other non-directory entry). _canonical_directory checks resolved.is_dir() after strict resolution so workspaces always point at real directories.

Source

Thrown at libs/code/deepagents_code/workspace.py:89

    if not isinstance(value, str) or not value or len(value) > _MAX_PATH_LENGTH:
        msg = f"workspace.{field} must be a non-empty absolute path"
        raise ValueError(msg)
    candidate = Path(value)
    if not candidate.is_absolute() or ".." in PurePath(value).parts:
        msg = f"workspace.{field} must be an absolute path without traversal"
        raise ValueError(msg)
    if os.name != "nt":
        from deepagents.backends.utils import validate_path

        validate_path(value)
    try:
        resolved = candidate.resolve(strict=True)
    except (OSError, RuntimeError) as exc:
        msg = f"workspace.{field} is unavailable: {value}"
        raise ValueError(msg) from exc
    if not resolved.is_dir():
        msg = f"workspace.{field} is not a directory: {value}"
        raise ValueError(msg)
    if os.name != "nt":
        from deepagents.backends.utils import validate_path

        validate_path(str(resolved))
    return resolved


def canonical_workspace_config(value: object | None) -> tuple[str, str]:
    """Return bounded canonical JSON and its SHA-256 fingerprint.

    Raises:
        TypeError: If the configuration is not an object.
        ValueError: If it cannot be serialized or exceeds the size limit.
    """
    if value is None:
        value = {}
    if not isinstance(value, dict):
        msg = "workspace_config must be an object"

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Point the workspace field at the directory, not a file: use the parent directory of the file.
  2. Create the intended directory if it does not exist.
  3. Verify with os.path.isdir / Path.is_dir before calling.

Example fix

// before
resolve_workspace(workspace={'dir': '/home/me/project/notes.md'})
// after
resolve_workspace(workspace={'dir': '/home/me/project'})
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(cfg['dir']).resolve(strict=True)
if not p.is_dir():
    raise NotADirectoryError(f'{p} is not a directory')

Type guard

def is_directory(value: str) -> bool:
    return Path(value).is_dir()

Try / catch

try:
    ws = resolve_workspace(workspace={'dir': cfg['dir']})
except ValueError as e:
    logger.error('workspace must be a directory: %s', e)

Prevention

When it happens

Trigger: Calling resolve_workspace with workspace.{field} set to a regular file path (e.g. /home/me/config.json) or any non-directory filesystem object.

Common situations: Config pointing at a file instead of its parent directory (copy-paste of a file path); a directory replaced by a file during refactoring; tools that wrote a file where a directory was expected.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/34b7c5079125e54c. Report an issue: GitHub.