{"record":{"id":"25ee3b0961db94ff","repo":"docker/compose","slug":"failed-to-access-env-file-s-w","errorCode":null,"errorMessage":"failed to access env file %s: %w","messagePattern":"failed to access env file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/compose/publish.go","lineNumber":263,"sourceCode":"\t}, func(options *loader.Options) {\n\t\toptions.SkipValidation = true\n\t\toptions.SkipExtends = true\n\t\toptions.SkipConsistencyCheck = true\n\t\toptions.ResolvePaths = true\n\t\toptions.SkipInclude = true\n\t\toptions.Profiles = project.Profiles\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor name, service := range base.Services {\n\t\tfor i, envFile := range service.EnvFiles {\n\t\t\t// A real stat failure (e.g. permissions) is fatal, but a missing file is not:\n\t\t\t// the project loader already rejects missing required env files before we get\n\t\t\t// here, so an absent file at this point is an optional one.\n\t\t\t_, statErr := os.Stat(envFile.Path)\n\t\t\tif statErr != nil && !os.IsNotExist(statErr) {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to access env file %s: %w\", envFile.Path, statErr)\n\t\t\t}\n\t\t\t// The hash is derived from the path string alone, so the env_file is always\n\t\t\t// rewritten to its opaque <hash>.env placeholder, even for a missing optional\n\t\t\t// file, so the published artifact never leaks the local path. Only files that\n\t\t\t// exist are registered for upload, mirroring the extends handling below.\n\t\t\thash := fmt.Sprintf(\"%x.env\", sha256.Sum256([]byte(envFile.Path)))\n\t\t\tif statErr == nil {\n\t\t\t\tenvFiles[envFile.Path] = hash\n\t\t\t}\n\t\t\tf, err = transform.ReplaceEnvFile(f, name, i, hash)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tif service.Extends == nil {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/compose/publish.go#L245-L281","documentation":"Thrown while preparing a Compose application for publishing when os.Stat on a service's env_file fails with an error other than 'file does not exist' (for example EACCES or a path component that is not a directory). A missing optional env file is deliberately tolerated, but any other filesystem error aborts publishing because the tool cannot determine whether the file should be uploaded as part of the artifact.","triggerScenarios":"Calling the publish API on a project whose service has env_file pointing to a path the current user cannot stat: permission denied on the file or a parent directory, or a path where an intermediate component is a regular file (ENOTDIR). Only non-ENOENT stat errors trigger it; absent optional files fall through.","commonSituations":"Running docker compose publish as a different user than the one owning the env file (common in CI with restrictive umasks), env_file under a directory with mode 700 owned by another user, or a typo that makes an intermediate path element a file instead of a directory.","solutions":["Check the path and permissions of the env_file value reported in the message: ls -l and namei -l <path> to find the failing component.","Grant read/execute on the file and every parent directory to the user running compose (chmod/chown), or move the env file to a readable location and update env_file.","If the file is intentionally optional and genuinely absent, remove the stale path from env_file or mark it with required: false so the missing-file case is tolerated instead of surfacing a stat error.","Fix ENOTDIR-style paths where a parent 'directory' is actually a file."],"exampleFix":"# before (docker-compose.yml)\nservices:\n  api:\n    env_file:\n      - /secure/keys/.env   # owned by root, mode 600\n\n# after\nservices:\n  api:\n    env_file:\n      - ./.env               # readable by the invoking user","handlingStrategy":"validation","validationCode":"func checkEnvFilesAccessible(project *types.Project) error {\n\tfor _, svc := range project.Services {\n\t\tfor _, ef := range svc.EnvFiles {\n\t\t\tif _, err := os.Stat(ef.Path); err != nil && !os.IsNotExist(err) {\n\t\t\t\treturn fmt.Errorf(\"env file %s not accessible: %w\", ef.Path, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := publishAPI(...); err != nil {\n\tif strings.Contains(err.Error(), \"failed to access env file\") {\n\t\t// surface the path from the message, check permissions, retry after fix\n\t}\n\treturn err\n}","preventionTips":["Run compose from a user that can read all referenced env files (verify with namei -l).","Keep env files inside the project directory with standard 644 permissions.","Lint compose files in CI for env_file paths that do not exist or are not readable."],"tags":["compose","publish","env-file","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}