docker/compose · error
git subdirectory must be relative, got: %s
Error message
git subdirectory must be relative, got: %s
What it means
`validateGitSubDir` guards the sub-directory fragment of a git remote include. This variant fires when the cleaned sub-path is absolute — e.g. starts with `/` on Unix. The loader refuses absolute sub-paths because they cannot be joined onto the checkout root safely.
Source
Thrown at pkg/remote/git.go:144
}
if stat.IsDir() {
local, err = findFile(cli.DefaultFileNames, local)
}
return local, err
}
func (g gitRemoteLoader) Dir(path string) string {
return g.known[path]
}
// validateGitSubDir ensures a subdirectory path is contained within the base directory
// and doesn't escape via path traversal. Unlike validatePathInBase for OCI artifacts,
// this allows nested directories but prevents traversal outside the base.
func validateGitSubDir(base, subDir string) error {
cleanSubDir := filepath.Clean(subDir)
if filepath.IsAbs(cleanSubDir) {
return fmt.Errorf("git subdirectory must be relative, got: %s", subDir)
}
if cleanSubDir == ".." || strings.HasPrefix(cleanSubDir, "../") || strings.HasPrefix(cleanSubDir, "..\\") {
return fmt.Errorf("git subdirectory path traversal detected: %s", subDir)
}
if len(cleanSubDir) >= 2 && cleanSubDir[1] == ':' {
return fmt.Errorf("git subdirectory must be relative, got: %s", subDir)
}
targetPath := filepath.Join(base, cleanSubDir)
cleanBase := filepath.Clean(base)
cleanTarget := filepath.Clean(targetPath)
// Ensure the target starts with the base path
relPath, err := filepath.Rel(cleanBase, cleanTarget)
if err != nil {
return fmt.Errorf("invalid git subdirectory path: %w", err)View on GitHub (pinned to ddc4b044b6)
Solutions
- Remove the leading slash: use `git://host/repo.git#main:subdir` not `git://host/repo.git#main:/subdir`
- Keep the fragment relative to the repository root
Example fix
# before include: - path: git://github.com/org/repo.git#main:/compose/prod # after include: - path: git://github.com/org/repo.git#main:compose/prod
Defensive patterns
Strategy: validation
Validate before calling
# keep include fragments relative (no leading slash)
python3 - <<'EOF'
import sys
for arg in sys.argv[1:]:
frag = arg.split('#', 1)[1] if '#' in arg else ''
sub = frag.split(':', 1)[1] if ':' in frag else ''
if sub.startswith(('/', '\\')):
sys.exit(f"absolute include fragment: {arg}")
EOF "$@" Prevention
- Author git include fragments relative to the repo root, mirror-image of local relative paths
- Code-review include paths for leading slashes after ref (`#main:/sub` is invalid)
When it happens
Trigger: An include path like `git://host/repo.git#main:/etc/config` where the fragment after the ref parses as an absolute path; also a Windows path like `\server\share` cleaning to an absolute form.
Common situations: Users writing sub-paths with a leading slash out of habit; converting a local `include: /abs/path` to a git include and keeping the leading slash; copy-paste from shell examples with absolute paths.
Related errors
- invalid git subdirectory path: %w
- COMPOSE_EXPERIMENTAL_GIT_REMOTE environment variable expects
- git remote resource is disabled by %q
- initializing remote resource cache: %w
- git subdirectory path traversal detected: %s
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/b6c3771a9c75e192.
Report an issue: GitHub.