docker/compose · error
invalid OCI artifact
Error message
invalid OCI artifact
What it means
First guard of `validatePathInBase` for `oci://` includes: OCI artifact resources must all live in a single flat directory, so any fragment containing `/` or `\` is rejected outright with the generic 'invalid OCI artifact' message. This differs from the git loader, which allows nested subdirectories.
Source
Thrown at pkg/remote/oci.go:52
"github.com/docker/cli/cli/command"
spec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/docker/compose/v5/internal/desktop"
"github.com/docker/compose/v5/internal/oci"
"github.com/docker/compose/v5/pkg/api"
)
const (
OCI_REMOTE_ENABLED = "COMPOSE_EXPERIMENTAL_OCI_REMOTE"
OciPrefix = "oci://"
)
// validatePathInBase ensures a file path is contained within the base directory,
// as OCI artifact resources must all live within the same folder.
func validatePathInBase(base, unsafePath string) error {
// Reject paths with path separators regardless of OS
if strings.ContainsAny(unsafePath, "\\/") {
return fmt.Errorf("invalid OCI artifact")
}
// Join the base with the untrusted path
targetPath := filepath.Join(base, unsafePath)
// Get the directory of the target path
targetDir := filepath.Dir(targetPath)
// Clean both paths to resolve any .. or . components
cleanBase := filepath.Clean(base)
cleanTargetDir := filepath.Clean(targetDir)
// Check if the target directory is the same as base directory
if cleanTargetDir != cleanBase {
return fmt.Errorf("invalid OCI artifact")
}
return nilView on GitHub (pinned to ddc4b044b6)
Solutions
- Package the OCI artifact so the compose file sits at its root and reference it with no path fragment: `oci://registry/repo:tag`
- Use a git:// include instead if you genuinely need nested subdirectory selection
Example fix
# before include: - path: oci://registry.example.com/team/configs:1.0#prod/compose.yaml # after include: - path: oci://registry.example.com/team/configs:1.0
Defensive patterns
Strategy: validation
Validate before calling
# oci:// fragments must be a bare filename: no / or \
python3 - <<'EOF'
import sys
for arg in sys.argv[1:]:
if not arg.startswith('oci://'): continue
frag = arg.split('#',1)[1] if '#' in arg else ''
if '/' in frag or '\\' in frag:
sys.exit(f"oci include fragment must be a flat filename: {arg}")
EOF Prevention
- Package OCI artifacts flat: the compose file at the artifact root, no nested directories
- Remember the oci:// and git:// include rules differ — oci has no subdirectory support
When it happens
Trigger: Including `oci://registry/repo:tag#sub/dir/compose.yaml` — any `#fragment` with a path separator fails, because the extracted files must sit directly in the base directory.
Common situations: Reusing git-include muscle memory (`#subdir/path`) with oci:// includes; OCI artifacts packaged with nested layouts that Compose cannot address.
Related errors
- git remote resource is disabled by %q
- git subdirectory must be relative, got: %s
- invalid git subdirectory path: %w
- repository does not contain ref %s, output: %q: %w
- COMPOSE_EXPERIMENTAL_OCI_REMOTE environment variable expects
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/55d0712216458085.
Report an issue: GitHub.