{"record":{"id":"282afed6a5e93461","repo":"langchain-ai/deepagents","slug":"workspace-field-must-be-an-absolute-path-without","errorCode":null,"errorMessage":"workspace.{field} must be an absolute path without traversal","messagePattern":"workspace\\.(.+?) must be an absolute path without traversal","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/workspace.py","lineNumber":77,"sourceCode":"\n\ndef _database_path() -> Path:\n    value = os.environ.get(f\"{SERVER_ENV_PREFIX}DB_PATH\")\n    if value:\n        return Path(value)\n    from deepagents_code.sessions import get_db_path\n\n    return get_db_path()\n\n\ndef _canonical_directory(value: object, *, field: str) -> Path:\n    if not isinstance(value, str) or not value or len(value) > _MAX_PATH_LENGTH:\n        msg = f\"workspace.{field} must be a non-empty absolute path\"\n        raise ValueError(msg)\n    candidate = Path(value)\n    if not candidate.is_absolute() or \"..\" in PurePath(value).parts:\n        msg = f\"workspace.{field} must be an absolute path without traversal\"\n        raise ValueError(msg)\n    if os.name != \"nt\":\n        from deepagents.backends.utils import validate_path\n\n        validate_path(value)\n    try:\n        resolved = candidate.resolve(strict=True)\n    except (OSError, RuntimeError) as exc:\n        msg = f\"workspace.{field} is unavailable: {value}\"\n        raise ValueError(msg) from exc\n    if not resolved.is_dir():\n        msg = f\"workspace.{field} is not a directory: {value}\"\n        raise ValueError(msg)\n    if os.name != \"nt\":\n        from deepagents.backends.utils import validate_path\n\n        validate_path(str(resolved))\n    return resolved\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/workspace.py#L59-L95","documentation":"Raised when a workspace path is either relative or contains '..' traversal segments. _canonical_directory requires absolute paths and forbids traversal to keep workspaces confined to an explicit location. This runs after the non-empty/length check and before filesystem resolution.","triggerScenarios":"Calling resolve_workspace with workspace.{field} like 'myproject', './myproject', '/a/b/../../etc', or any path where PurePath parts contain '..'.","commonSituations":"Configured with a relative path because a tilde/env expansion never happened ('~/work' is not absolute until expanded); '..' segments introduced by joining user-supplied segments; security policy rejecting traversal.","solutions":["Use an absolute path with no '..' components, e.g. /home/me/project.","Expand '~' with os.path.expanduser and absolutize with Path.resolve()/abspath before calling.","Strip or normalize '..' segments in paths built from user input."],"exampleFix":"// before\nresolve_workspace(workspace={'dir': '~/work'})\n// after\nimport os\nresolve_workspace(workspace={'dir': os.path.expanduser('~/work')})","handlingStrategy":"validation","validationCode":"from pathlib import Path, PurePath\nimport os\n\ndef absolutize(value: str) -> str:\n    expanded = os.path.expanduser(value)\n    absolute = str(Path(expanded).absolute())\n    if '..' in PurePath(absolute).parts:\n        raise ValueError('.. segments not allowed')\n    return absolute","typeGuard":"def is_absolute_no_traversal(value: str) -> bool:\n    p = PurePath(value)\n    return p.is_absolute() and '..' not in p.parts","tryCatchPattern":"try:\n    ws = resolve_workspace(workspace={'dir': cfg['dir']})\nexcept ValueError as e:\n    logger.error('workspace path must be absolute without traversal: %s', e)","preventionTips":["Run expanduser/expandvars on tilde and env-var paths before use","Reject '..' segments early when building paths from user input","Store absolute canonical paths in config files"],"tags":["validation","path","workspace","security"],"backgroundTag":"invalid-path","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}