docker/compose · error

failed to parse env_file

Error message

failed to parse env_file %s: %w

What it means

When compose reads an env_file (--env-file, or the command-level env-file handling that uses rawEnv), it parses it with docker/cli's key=value parser. Any line that does not conform (unterminated quote, invalid shell-ish syntax, BOM/encoding issues) makes ParseFromReader fail, and rawEnv wraps the failure with the offending file name.

Solutions

  1. Open the named file at the reported path and fix the malformed line (usually an unterminated quote or a line missing '=')
  2. Normalize the file: UTF-8, LF endings, KEY=VALUE per line, quote values containing spaces symmetrically
  3. Validate quickly: `docker run --rm -v $PWD:/w alpine sh -c 'set -a; . /w/.env'` or a linter such as dotenv-linter
  4. If the file is generated, ensure the generator escapes quotes/newlines correctly

Example fix

# before (.env)
APP_ARGS="--foo bar      # unterminated quote
# after (.env)
APP_ARGS="--foo bar"
Defensive patterns

Strategy: validation

Validate before calling

python3 - <<'EOF'
import sys
for fn in sys.argv[1:]:
    for i,l in enumerate(open(fn, encoding='utf-8'), 1):
        s=l.strip()
        if not s or s.startswith('#'): continue
        if '"' in s and s.count('"') % 2: sys.exit(f"{fn}:{i} unbalanced quote")
        if '=' not in s: sys.exit(f"{fn}:{i} missing =")
print('env files ok')
EOF .env

Prevention

When it happens

Trigger: Passing --env-file .env.crashed with a malformed line (e.g. VALUE="unterminated, stray backslash, or a line without '='), or a file saved with CRLF/BOM or non-UTF8 bytes.

Common situations: Windows-edited env files with CRLF or smart quotes; a missing closing quote after editing values with spaces; secrets injected into env files breaking quoting; empty lines are fine but lines like `export FOO=bar` (the export prefix) can trip strict parsers depending on version.

Understand the failure class

Related errors


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

Appendix: source

Thrown at cmd/compose/compose.go:79

	// ComposeCompatibility try to mimic compose v1 as much as possible
	ComposeCompatibility = api.ComposeCompatibility
	// ComposeRemoveOrphans remove "orphaned" containers, i.e. containers tagged for current project but not declared as service
	ComposeRemoveOrphans = "COMPOSE_REMOVE_ORPHANS"
	// ComposeIgnoreOrphans ignore "orphaned" containers
	ComposeIgnoreOrphans = "COMPOSE_IGNORE_ORPHANS"
	// ComposeEnvFiles defines the env files to use if --env-file isn't used
	ComposeEnvFiles = "COMPOSE_ENV_FILES"
	// ComposeMenu defines if the navigation menu should be rendered. Can be also set via --menu
	ComposeMenu = "COMPOSE_MENU"
	// ComposeProgress defines type of progress output, if --progress isn't used
	ComposeProgress = "COMPOSE_PROGRESS"
)

// rawEnv load a dot env file using docker/cli key=value parser, without attempt to interpolate or evaluate values
func rawEnv(r io.Reader, filename string, vars map[string]string, lookup func(key string) (string, bool)) error {
	lines, err := kvfile.ParseFromReader(r, lookup)
	if err != nil {
		return fmt.Errorf("failed to parse env_file %s: %w", filename, err)
	}
	for _, line := range lines {
		key, value, _ := strings.Cut(line, "=")
		vars[key] = value
	}
	return nil
}

var stdioToStdout bool

func init() {
	// compose evaluates env file values for interpolation
	// `raw` format allows to load env_file with the same parser used by docker run --env-file
	dotenv.RegisterFormat("raw", rawEnv)

	if v, ok := os.LookupEnv("COMPOSE_STATUS_STDOUT"); ok {
		stdioToStdout, _ = strconv.ParseBool(v)
	}

View on GitHub (pinned to ddc4b044b6)