datawhalechina/hello-agents · error · PatchApplyError
Absolute paths are not allowed: {rel_path}
Error message
Absolute paths are not allowed: {rel_path} What it means
Raised by _safe_path when the rel_path argument begins with '/' or '~', i.e. the caller passed an absolute POSIX path or a home-relative path instead of a path relative to repo_root. The executor deliberately confines all writes to repo_root, so absolute targets are rejected before any filesystem access.
Source
Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py:200
# 返回最终的应用结果
return ApplyResult(files_changed=files_changed, backups=backups)
def _safe_path(self, rel_path: str) -> Path:
"""
验证路径安全性,防止路径遍历攻击 (Path Traversal)。
确保目标路径在 repo_root 目录下,防止访问仓库外的文件。
参数:
rel_path: 相对路径字符串
返回:
Path: 安全的绝对路径对象
异常:
PatchApplyError: 当路径是绝对路径、包含特殊字符或试图访问仓库外时抛出
"""
if rel_path.startswith("/") or rel_path.startswith("~"):
raise PatchApplyError(f"Absolute paths are not allowed: {rel_path}")
target = (self.repo_root / rel_path).resolve()
# 检查解析后的路径是否以 repo_root 开头
if not str(target).startswith(str(self.repo_root.resolve()) + os.sep) and target != self.repo_root.resolve():
raise PatchApplyError(f"Path escapes repo_root: {rel_path}")
if target.exists() and target.is_symlink():
raise PatchApplyError(f"Refusing to modify symlink: {rel_path}")
return target
def _enforce_suffix(self, target: Path) -> None:
"""
检查目标文件的后缀是否在允许的列表中。
防止意外修改二进制文件、配置文件或其他敏感文件。
参数:
target: 目标文件路径对象
异常:
PatchApplyError: 当文件后缀不在允许列表中时抛出View on GitHub (pinned to 606a07d341)
Solutions
- Strip the repo_root prefix (or re-relativize) before building the patch: rel = os.path.relpath(abs_path, repo_root).
- Fix the patch text so file headers use repo-relative paths like 'src/main.py'.
- If the intent really is to write outside the repo, instantiate the executor with a repo_root that contains the target, rather than bypassing the guard.
Example fix
# before '*** Update File: /home/user/proj/src/main.py' # after from pathlib import Path rel = Path(abs_path).relative_to(repo_root).as_posix() # 'src/main.py' # use '*** Update File: src/main.py' in the patch
Defensive patterns
Strategy: validation
Validate before calling
def to_rel(abs_or_rel: str, repo_root: Path) -> str:
p = Path(abs_or_rel)
if p.is_absolute() or abs_or_rel.startswith('~'):
p = Path(os.path.expanduser(abs_or_rel))
return p.resolve().relative_to(repo_root.resolve()).as_posix()
return abs_or_rel
rel = to_rel(model_path, repo_root)
assert not rel.startswith(('/', '~')), 'must be repo-relative' Type guard
def is_repo_relative(rel_path: str) -> bool:
return not rel_path.startswith('/') and not rel_path.startswith('~') Try / catch
try:
executor.apply(patch)
except PatchApplyError as e:
if 'Absolute paths are not allowed' in str(e):
patch = rewrite_paths_relative(patch, repo_root)
executor.apply(patch)
else:
raise Prevention
- Always emit repo-relative posix paths in patch file headers.
- Relativize any absolute path from tool output before embedding it in a patch.
- Unit-test the patch builder against absolute-path leakage.
When it happens
Trigger: Passing '/etc/passwd', '~/notes.md', or any path starting with '/' as the file path in an '*** Add File: ' / '*** Update File: ' section of the patch; LLM-generated patches that emit absolute paths copied from tool output.
Common situations: Agent models echoing absolute paths from a previous tool result; patches authored on a different machine with absolute paths; scripts reusing a resolved Path object where a relative string is expected.
Related errors
- Path escapes repo_root: {rel_path}
- Refusing to modify symlink: {rel_path}
- Unknown op kind: {kind}
- Disallowed file suffix for write: {target.suffix}
- Patch must start with '*** Begin Patch'
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/e35493fd2beb0d4b.
Report an issue: GitHub.