BerriAI/litellm · error · HTTPException
git-subdir source must include 'path' field (e.g., 'plugins/
Error message
git-subdir source must include 'path' field (e.g., 'plugins/plugin-name')
What it means
400 thrown by _validate_plugin_source() for a git-subdir source that has a url but no "path" key. LiteLLM needs the subdirectory inside the repository where the plugin lives; without it the source would be equivalent to a plain url source.
Source
Thrown at litellm/proxy/anthropic_endpoints/claude_code_endpoints/claude_code_marketplace.py:190
status_code=400,
detail={"error": "GitHub source must include 'repo' field (e.g., 'org/repo')"},
)
elif source_type == "url":
if "url" not in source:
raise HTTPException(
status_code=400,
detail={"error": "URL source must include 'url' field (e.g., 'https://github.com/org/repo.git')"},
)
elif source_type == "git-subdir":
if not source.get("url"):
raise HTTPException(
status_code=400,
detail={
"error": "git-subdir source must include 'url' field (e.g., 'https://github.com/org/repo.git')"
},
)
if not source.get("path"):
raise HTTPException(
status_code=400,
detail={"error": "git-subdir source must include 'path' field (e.g., 'plugins/plugin-name')"},
)
if not _VALID_GIT_SUBDIR_PATH_RE.match(source["path"]):
raise HTTPException(
status_code=400,
detail={
"error": "git-subdir 'path' must be a relative path of the form 'segment/segment' (alphanumeric, dots, hyphens, underscores only)"
},
)
else:
raise HTTPException(
status_code=400,
detail={"error": "source.source must be 'github', 'url', or 'git-subdir'"},
)
def _build_plugin_manifest(name: str, spec: PluginSpec) -> Mapping[str, object]:View on GitHub (pinned to 77b7c6c40c)
Solutions
- Add the path field with the plugin's directory relative to the repo root: "path": "plugins/plugin-name".
- Use exactly the key 'path'; then make sure its value passes the segment/segment regex (no leading '/', no '..' segments, no backslashes).
- If the plugin actually lives at the repo root, use source type "url" instead of git-subdir.
Example fix
# before
{"source": {"source": "git-subdir", "url": "https://github.com/org/monorepo.git"}}
# after
{"source": {"source": "git-subdir", "url": "https://github.com/org/monorepo.git", "path": "plugins/plugin-name"}} Defensive patterns
Strategy: validation
Validate before calling
source = payload["source"]
if source.get("source") == "git-subdir" and not source.get("path"):
raise ValueError("git-subdir source requires a non-empty 'path' (e.g. 'plugins/plugin-name')") Type guard
function hasSubdirPath(s: unknown): boolean {
const o = s as Record<string, unknown>;
return typeof o?.path === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9._-]*(\/[a-zA-Z0-9][a-zA-Z0-9._-]*)*$/.test(o.path);
} Prevention
- Compute path from the repo layout (never free-typed) and assert it is a non-empty relative path.
- CI-lint plugin manifests so a git-subdir entry without path fails before it reaches the proxy.
When it happens
Trigger: POST /claude-code/plugins or PUT /claude-code/plugins/{name} with {"source": {"source": "git-subdir", "url": "https://github.com/org/monorepo.git"}} — path key missing. The check is truthiness-based, so "path": "" also fails.
Common situations: Registering a monorepo plugin and forgetting the directory; using a key like "dir", "subdir", or "subpath" instead of 'path'; path built from a variable that is None/empty at runtime.
Related errors
- GitHub source must include 'repo' field (e.g., 'org/repo')
- URL source must include 'url' field (e.g., 'https://github.c
- git-subdir source must include 'url' field (e.g., 'https://g
- source.source must be 'github', 'url', or 'git-subdir'
- Plugin name must be kebab-case (lowercase letters, numbers,
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/29cf07869874dd8d.
Report an issue: GitHub.