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
- Open the named file at the reported path and fix the malformed line (usually an unterminated quote or a line missing '=')
- Normalize the file: UTF-8, LF endings, KEY=VALUE per line, quote values containing spaces symmetrically
- Validate quickly: `docker run --rm -v $PWD:/w alpine sh -c 'set -a; . /w/.env'` or a linter such as dotenv-linter
- 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
- Run dotenv-linter over env files in CI
- Save env files as UTF-8 with LF endings; avoid smart quotes from word processors
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- parsing failed
- %s must be an integer (found: %q)
- invalid --scale option %q. Should be SERVICE=NUM
- label must be set as KEY=VALUE
- loading otel config from docker context metadata: %w
AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15).
Data as JSON: /api/errors/3678715c83b071b8.
Report an issue: GitHub.