shareAI-lab/learn-claude-code · error · GoalError

path escapes the current repository

Error message

path escapes the current repository

What it means

AgentSession._safe_path resolved a tool-supplied relative path (workdir / path, then .resolve()) and found it does not lie inside self.workdir (s17_goal_loop/code.py:753). The resolution step follows symlinks and '../' segments, so this fires on sandbox escapes like '../../etc/passwd', absolute-path tricks after joining, or a symlink inside the repo pointing outside.

Source

Thrown at s17_goal_loop/code.py:753

                            f"Evaluator: {decision.reason}\n"
                            "Continue working and surface the missing evidence."
                        ),
                    }
                )
                continue
            self.trigger_hooks("Stop", self.messages)
            return SessionResult(
                text=text,
                status=decision.action,
                reason=decision.reason,
            )

    def _safe_path(self, path: str) -> Path:
        candidate = (self.workdir / path).resolve()
        try:
            candidate.relative_to(self.workdir)
        except ValueError as error:
            raise GoalError("path escapes the current repository") from error
        return candidate

    def _run_tool(self, name: str, arguments: dict[str, Any]) -> str:
        if name == "bash":
            command = str(arguments["command"])
            result = subprocess.run(
                command,
                shell=True,
                cwd=self.workdir,
                capture_output=True,
                text=True,
                timeout=120,
                check=False,
            )
            output = (result.stdout + result.stderr).strip()
            output = output[-29950:]
            return f"exit_code={result.returncode}\n{output}"

View on GitHub (pinned to 985456f4ad)

Solutions

  1. If the access is legitimate, copy the needed file into the repo or run the session with a workdir that contains it
  2. Rephrase the task so the model only references in-repo paths; add the constraint to the system/task prompt
  3. Remove or relocate symlinks inside the repo that point outside the root
  4. Catch GoalError around session runs and treat it as a tool-misuse signal: log and let the agent retry with a corrected path

Example fix

# before
# model tool call: read_file ../../~/.gitconfig

# after
# copy the file into the repo first, then let the model read it
cp ~/.gitconfig ./.gitconfig.reference
# model tool call: read_file .gitconfig.reference
Defensive patterns

Strategy: try-catch

Validate before calling

def resolves_inside(workdir: Path, relative: str) -> bool:
    try:
        (workdir / relative).resolve().relative_to(workdir.resolve())
        return True
    except ValueError:
        return False

if not resolves_inside(session.workdir, tool_args.get("path", "")):
    # reject or rewrite the path before dispatching the tool

Type guard

def is_safe_relative_path(workdir: Path, path: object) -> bool:
    if not isinstance(path, str) or not path:
        return False
    try:
        (workdir / path).resolve().relative_to(workdir.resolve())
        return True
    except ValueError:
        return False

Try / catch

try:
    await session.submit(query)
except GoalError as error:
    if "escapes the current repository" in str(error):
        log.warning("tool attempted out-of-repo path; retrying with constrained prompt")
        continue  # let the agent see the error and choose an in-repo path
    raise

Prevention

When it happens

Trigger: A tool call (read/write/edit) from the model passes a path containing '..' that escapes the repo root, or a path that resolves through a symlink to a location outside workdir. For example read_file with '../../~/.ssh/config' while workdir is the repo.

Common situations: The model tries to read config or logs outside the project (e.g. ~/.gitconfig, /tmp artifacts); the repo contains a symlink (node_modules-style links, linked assets) to an external directory; generated code passes absolute paths which get joined and resolve outside root.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/9c53536fae066f26. Report an issue: GitHub.