modelcontextprotocol/servers · error · ValueError
Invalid path: {repo_path}
Error message
Invalid path: {repo_path} What it means
validate_repo_path() resolves both repo_path and the configured allowed_repository with Path.resolve(); if resolve() raises OSError or RuntimeError (broken symlink, symlink loop, illegal characters, permission error), it is rethrown as ValueError 'Invalid path: ...'. This is the resolve step; the separate outside-repo check produces a different message. validate_repo_path is a no-op when allowed_repository (the server's repository argument) is None.
Source
Thrown at src/git/src/mcp_server_git/server.py:262
if d.diff is None:
continue
if isinstance(d.diff, bytes):
output.append(d.diff.decode('utf-8'))
else:
output.append(d.diff)
return "".join(output)
def validate_repo_path(repo_path: Path, allowed_repository: Path | None) -> None:
"""Validate that repo_path is within the allowed repository path."""
if allowed_repository is None:
return # No restriction configured
# Resolve both paths to handle symlinks and relative paths
try:
resolved_repo = repo_path.resolve()
resolved_allowed = allowed_repository.resolve()
except (OSError, RuntimeError):
raise ValueError(f"Invalid path: {repo_path}")
# Check if repo_path is the same as or a subdirectory of allowed_repository
try:
resolved_repo.relative_to(resolved_allowed)
except ValueError:
raise ValueError(
f"Repository path '{repo_path}' is outside the allowed repository '{allowed_repository}'"
)
def git_branch(repo: git.Repo, branch_type: str, contains: str | None = None, not_contains: str | None = None) -> str:
# Defense in depth: reject values starting with '-' to prevent flag injection
if contains and contains.startswith("-"):
raise BadName(f"Invalid contains value: '{contains}' - cannot start with '-'")
if not_contains and not_contains.startswith("-"):
raise BadName(f"Invalid not_contains value: '{not_contains}' - cannot start with '-'")
match contains:View on GitHub (pinned to 76d64c822f)
Solutions
- Pass a repo_path that is an existing, valid directory resolvable on the server host.
- Use a repo_path returned by list_repos() (derived from Roots or the configured repository).
- Ensure the allowed_repository itself resolves correctly.
Example fix
# before
validate_repo_path(Path('/tmp/broken-symlink'), allowed_repository=Path('/repo')) # -> ValueError
# after
p = Path(repo_path)
if not p.is_dir():
raise ValueError('repo_path must be an existing directory')
validate_repo_path(p.resolve(), allowed_repository=Path('/repo')) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def valid_repo_path(repo_path: Path, allowed: Path | None) -> None:
if allowed is None:
return
if not repo_path.is_dir():
raise ValueError(f'Invalid path: {repo_path}')
resolved = repo_path.resolve()
if not resolved.is_relative_to(allowed.resolve()):
raise ValueError(f'Repository path {repo_path} is outside the allowed repository {allowed}') Try / catch
try:
validate_repo_path(repo_path, allowed_repository)
except ValueError as e:
if e.args[0].startswith('Invalid path:'):
# pick a repo_path from list_repos() instead
raise Prevention
- Pass repo_path values returned by list_repos() rather than user-typed paths.
- Ensure the path is an existing, resolvable directory before calling.
- Keep the allowed_repository (server repository arg) consistent across calls.
When it happens
Trigger: Client passes a repo_path that is a broken symlink, a loop, or contains illegal characters while an allowed_repository is configured.
Common situations: Client supplies a stale or non-existent path; symlinked repo roots whose target is missing; permission issues on the path.
Related errors
- Invalid path: '{f}'
- Invalid target: '{target}' - cannot start with '-'
- Path '{f}' is outside the repository '{repo_root}'
- Invalid start_timestamp: '{start_timestamp}' - cannot start
- Invalid end_timestamp: '{end_timestamp}' - cannot start with
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/a6a7774d76a6070e.
Report an issue: GitHub.