modelcontextprotocol/servers · error · BadName
Invalid not_contains value: '{not_contains}' - cannot start
Error message
Invalid not_contains value: '{not_contains}' - cannot start with '-' What it means
Same defense-in-depth guard in git_branch (server.py:277-278) for the 'not_contains' argument, which would otherwise be forwarded to repo.git.branch('--no-contains', not_contains). A leading '-' is rejected with git.exc.BadName to prevent flag injection.
Source
Thrown at src/git/src/mcp_server_git/server.py:278
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:
case None:
contains_sha = (None,)
case _:
contains_sha = ("--contains", contains)
match not_contains:
case None:
not_contains_sha = (None,)
case _:
not_contains_sha = ("--no-contains", not_contains)
match branch_type:
case 'local':
b_type = None
case 'remote':
b_type = "-r"View on GitHub (pinned to 76d64c822f)
Solutions
- Pass the bare ref or commit as 'not_contains' (e.g. 'main'), not '--no-contains main'.
- Strip a leading '--no-contains=' prefix from user input if present.
- Reject any value starting with '-' before sending the call.
- Share one ref-sanitization helper across contains and not_contains.
Example fix
// before // not_contains: "--no-contains main" -> BadName // after // not_contains: "main"
Defensive patterns
Strategy: validation
Validate before calling
def clean_ref_arg(v: str | None) -> str | None:
if v is None:
return None
v = v.strip()
if v.startswith("--no-contains="):
v = v[len("--no-contains="):]
if v.startswith("-"):
raise ValueError(f"ref argument must not start with '-': {v!r}")
if not v:
return None
return v
not_contains = clean_ref_arg(arguments.get("not_contains")) Type guard
def is_safe_ref_arg(v: object) -> bool:
return v is None or (isinstance(v, str) and not v.startswith("-") and v.strip() != "") Try / catch
from git.exc import BadName
try:
result = git_branch(repo, branch_type, contains, not_contains)
except BadName as e:
log.warning("rejected ref arg: %s", e) Prevention
- Pass the bare ref as not_contains, never '--no-contains main'.
- Strip '--no-contains=' from pasted input.
- Share the same sanitizer used for contains and other ref arguments.
When it happens
Trigger: Calling the branch tool with a 'not_contains' value beginning with '-', e.g. '-r', '--merged', '--no-contains=main'. Typically a user/LLM copying the '--no-contains X' literal into the value slot.
Common situations: Translating 'git branch --no-contains main' into tool args naively. Reusing a flag string across contains/not_contains. Hallucinated prefixes.
Related errors
- Invalid target: '{target}' - cannot start with '-'
- Invalid start_timestamp: '{start_timestamp}' - cannot start
- Invalid end_timestamp: '{end_timestamp}' - cannot start with
- Invalid branch name: '{branch_name}' - cannot start with '-'
- Invalid base branch: '{base_branch}' - cannot start with '-'
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/3344b5971c07e366.
Report an issue: GitHub.