langchain-ai/deepagents · error · ValueError

project_root must be absolute, got {self.project_root!r}

Error message

project_root must be absolute, got {self.project_root!r}

What it means

ValueError raised in ProjectContext.__post_init__ when project_root is provided but is a relative path. Like user_cwd, project_root must be absolute so workspace binding and path comparisons remain unambiguous across processes.

Source

Thrown at libs/code/deepagents_code/project_utils.py:44

        user_cwd: Authoritative working directory from the app invocation.
        project_root: Resolved project root for `user_cwd`, if one exists.
    """

    user_cwd: Path
    project_root: Path | None = None

    def __post_init__(self) -> None:
        """Validate that path fields are absolute.

        Raises:
            ValueError: If `user_cwd` or `project_root` is not absolute.
        """
        if not self.user_cwd.is_absolute():
            msg = f"user_cwd must be absolute, got {self.user_cwd!r}"
            raise ValueError(msg)
        if self.project_root is not None and not self.project_root.is_absolute():
            msg = f"project_root must be absolute, got {self.project_root!r}"
            raise ValueError(msg)

    @classmethod
    def from_user_cwd(cls, user_cwd: str | Path) -> ProjectContext:
        """Build a project context from an explicit user working directory.

        Args:
            user_cwd: User invocation directory.

        Returns:
            Resolved project context.
        """
        resolved_cwd = Path(user_cwd).expanduser().resolve()
        return cls(
            user_cwd=resolved_cwd,
            project_root=find_project_root(resolved_cwd),
        )

    def resolve_user_path(self, path: str | Path) -> Path:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Resolve the root: project_root=Path(raw).resolve() before constructing the context
  2. Omit project_root (None) if there is no project, instead of passing a relative placeholder
  3. Fix the config/source so stored project roots are absolute

Example fix

// before
ctx = ProjectContext(user_cwd=cwd, project_root=Path(config["root"]))

// after
ctx = ProjectContext(user_cwd=cwd, project_root=Path(config["root"]).resolve())
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
root = Path(config["project_root"]).resolve() if config.get("project_root") else None
ctx = ProjectContext(user_cwd=cwd, project_root=root)

Type guard

def is_abs_or_none(p: object) -> TypeGuard[Path | None]:
    return p is None or (isinstance(p, Path) and p.is_absolute())

Try / catch

try:
    ctx = ProjectContext(user_cwd=cwd, project_root=root)
except ValueError as e:
    raise ConfigError(f"project_root must be absolute: {e}") from e

Prevention

When it happens

Trigger: Constructing ProjectContext(user_cwd=..., project_root=Path(".")) or any relative path; passing a relative root discovered from config or env vars. Note project_root=None is allowed.

Common situations: Reading project_root from a settings file stored as a relative path; passing "." or the result of os.getcwd() without resolve() on systems where it returns relative; partially migrated configs.

Related errors


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