docker/compose · error

failed to parse env_file %s: %w

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.

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)

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.