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

  1. Confirm the Dockerfile path is readable: `cat <path-to-dockerfile>` from the compose invocation directory
  2. Fix permissions (chmod 644) or repair/remove the symlink pointing at the Dockerfile
  3. 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

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


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/c00dec93de8a02df. Report an issue: GitHub.