docker/cli · error

invalid env file ( )

Error message

invalid env file (%s): %v

What it means

Returned by kvfile.Parse as a wrapper ('invalid env file (<filename>): <cause>') over any error produced while scanning an env/label file (invalid UTF-8, a line with no variable name, a key containing whitespace, or the bufio scanner error). The filename is interpolated so the offending file is identifiable; the underlying cause is in %v.

Solutions

  1. Read the wrapped cause in the error: it names the exact problem (UTF-8 line N, whitespace key, etc.).
  2. Re-save the file as UTF-8 (no BOM) in your editor.
  3. Fix the offending line: ensure 'KEY=value' with no spaces in KEY and a non-empty key.
  4. If using compose, point env_file at the corrected file and re-run.

Example fix

# before (broken.env, saved as UTF-16)
# after: re-encode as UTF-8
iconv -f UTF-16 -t UTF-8 broken.env > fixed.env
docker run --env-file fixed.env ...
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: file must be readable AND valid UTF-8 before kvfile.Parse.
import ("io"; "os"; "unicode/utf8")

func envFileLooksValid(name string) error {
    f, err := os.Open(name)
    if err != nil { return err }
    defer f.Close()
    buf := make([]byte, 64*1024)
    for {
        n, err := f.Read(buf)
        if !utf8.Valid(buf[:n]) { return fmt.Errorf("%s: invalid UTF-8", name) }
        if err == io.EOF { break }
        if err != nil { return err }
    }
    return nil
}

// if err := envFileLooksValid(file); err != nil { return err }

Try / catch

lines, err := kvfile.Parse(file, nil)
if err != nil {
    // err already wraps the cause: invalid env file (<file>): <cause>
    return fmt.Errorf("cannot load env file %q: %w", file, err)
}

Prevention

When it happens

Trigger: 'docker run --env-file broken.env ...' where broken.env has a non-UTF-8 byte, a line like '=value' (no key), or 'MY VAR=x' (whitespace in key). Also via --label-file, or compose env_file: that routes through kvfile.Parse.

Common situations: Env file saved in latin-1/UTF-16/Windows-1252, an editor inserting a BOM mid-file or smart-quotes, a stray space before '=' ('VAR =x'), or a line accidentally starting with '='. The wrapped message hides which line; open the file named in the message.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/28bb048b285e2eb4. Report an issue: GitHub.

Appendix: source

Thrown at pkg/kvfile/kvfile.go:66

	"os"
	"strings"
	"unicode"
	"unicode/utf8"
)

// Parse parses a line-delimited key/value pairs separated by equal sign.
// It accepts a lookupFn to lookup default values for keys that do not define
// a value. An error is produced if parsing failed, the content contains invalid
// UTF-8 characters, or a key contains whitespaces.
func Parse(filename string, lookupFn func(key string) (value string, found bool)) ([]string, error) {
	fh, err := os.Open(filename)
	if err != nil {
		return []string{}, err
	}
	out, err := parseKeyValueFile(fh, lookupFn)
	_ = fh.Close()
	if err != nil {
		return []string{}, fmt.Errorf("invalid env file (%s): %v", filename, err)
	}
	return out, nil
}

// ParseFromReader parses a line-delimited key/value pairs separated by equal sign.
// It accepts a lookupFn to lookup default values for keys that do not define
// a value. An error is produced if parsing failed, the content contains invalid
// UTF-8 characters, or a key contains whitespaces.
func ParseFromReader(r io.Reader, lookupFn func(key string) (value string, found bool)) ([]string, error) {
	return parseKeyValueFile(r, lookupFn)
}

const whiteSpaces = " \t"

func parseKeyValueFile(r io.Reader, lookupFn func(string) (string, bool)) ([]string, error) {
	lines := []string{}
	scanner := bufio.NewScanner(r)
	utf8bom := []byte{0xEF, 0xBB, 0xBF}

View on GitHub (pinned to 4f84911bfe)