docker/compose · error
unable to open Dockerfile: %w
Error message
unable to open Dockerfile: %w
What it means
After GetContextFromLocalDir succeeds, doBuildClassic special-cases a Dockerfile that resolves outside the build context (relDockerfile starts with '../'): it must open that file with os.Open to pass it separately as dockerfileCtx. If os.Open fails (file deleted between stat and open, permission denied, dangling symlink), this wrapped error is returned.
Source
Thrown at pkg/compose/build_classic.go:176
contextType, err := build.DetectContextType(specifiedContext)
if err != nil {
return "", err
}
switch contextType {
case build.ContextTypeStdin:
return "", fmt.Errorf("building from STDIN is not supported")
case build.ContextTypeLocal:
contextDir, relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, dockerfileName)
if err != nil {
return "", fmt.Errorf("unable to prepare context: %w", err)
}
if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
// Dockerfile is outside build-context; read the Dockerfile and pass it as dockerfileCtx
dockerfileCtx, err = os.Open(dockerfileName)
if err != nil {
return "", fmt.Errorf("unable to open Dockerfile: %w", err)
}
defer dockerfileCtx.Close() //nolint:errcheck
}
case build.ContextTypeGit:
var tempDir string
tempDir, relDockerfile, err = build.GetContextFromGitURL(specifiedContext, dockerfileName)
if err != nil {
return "", fmt.Errorf("unable to prepare context: %w", err)
}
defer func() {
_ = os.RemoveAll(tempDir)
}()
contextDir = tempDir
case build.ContextTypeRemote:
buildCtx, relDockerfile, err = build.GetContextFromURL(progBuff, specifiedContext, dockerfileName)
if err != nil {
return "", fmt.Errorf("unable to prepare context: %w", err)
}View on GitHub (pinned to ddc4b044b6)
Solutions
- Confirm the Dockerfile path is readable: `cat <path-to-dockerfile>` from the compose invocation directory
- Fix permissions (chmod 644) or repair/remove the symlink pointing at the Dockerfile
- Move (or copy) the Dockerfile inside the build context and reference it relatively, which also removes the outside-context special case
Example fix
# before
services:
api:
build:
context: ./services/api
dockerfile: ../../Dockerfile.api # unreadable/outside
# after
services:
api:
build:
context: .
dockerfile: Dockerfile.api Defensive patterns
Strategy: validation
Validate before calling
// when the Dockerfile sits outside the context, verify it is readable up front
absCtx, _ := filepath.Abs(svc.Build.Context)
absDf, _ := filepath.Abs(filepath.Join(svc.Build.Context, svc.Build.Dockerfile))
if strings.HasPrefix(absDf, absCtx+string(filepath.Separator)) == false {
if f, err := os.Open(absDf); err != nil {
return fmt.Errorf("dockerfile %q unreadable: %w", absDf, err)
} else { _ = f.Close() }
} Prevention
- Keep Dockerfiles inside their build context to avoid the outside-context branch entirely
- Check file permissions of shared Dockerfiles in Dockerfiles-as-code lint steps
When it happens
Trigger: A Compose build where `build.dockerfile` is an absolute path or relative path outside the context directory, and that file is unreadable — wrong permissions, nonexistent, or a broken symlink — at the moment the classic builder runs.
Common situations: Shared Dockerfile at repo root with per-service contexts (`context: services/api`, `dockerfile: ../../Dockerfile`); files made unreadable by restrictive umask or owned by another user in CI; a symlink to a Dockerfile that exists only on the developer's machine.
Related errors
- cannot take exclusive lock for project %q: %w
- stat %q: %w
- inspecting %q: %w
- walking %q: %w
- cannot create output folder: %w
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/c00dec93de8a02df.
Report an issue: GitHub.