docker/cli · error
invalid utf8 bytes at line
Error message
invalid utf8 bytes at line %d: %v
What it means
Returned inside parseKeyValueFile when bufio.Scanner.Bytes() for a line is not valid UTF-8. kvfile requires the whole file to be UTF-8 (a leading BOM is stripped on line 1, but any other invalid byte sequence fails). The line number and the raw bytes are included.
Solutions
- Re-encode the file to UTF-8 without BOM: 'iconv -f UTF-16 -t UTF-8 file.env > out.env' or 'dos2unix file.env'.
- Remove any mid-file BOM/zero-width characters.
- Validate with 'file --mime-encoding file.env' (expect utf-8) before passing it to Docker.
Example fix
# before: PowerShell wrote UTF-16 # after Get-Content file.env | Set-Content -Encoding utf8 file.env # or on unix: iconv -f UTF-16 -t UTF-8 file.env > file.utf8.env
Defensive patterns
Strategy: validation
Validate before calling
// Verify a file is UTF-8 (and strip/flag a BOM) before passing to kvfile.Parse.
import ("bytes"; "os"; "unicode/utf8")
func isUTF8File(name string) (bool, error) {
b, err := os.ReadFile(name)
if err != nil { return false, err }
b = bytes.TrimPrefix(b, []byte{0xEF, 0xBB, 0xBF}) // tolerate a leading BOM
return utf8.Valid(b), nil
}
// ok, _ := isUTF8File(file); if !ok { return fmt.Errorf("%s is not valid UTF-8", file) } Try / catch
if _, err := kvfile.Parse(file, lookup); err != nil {
return err // invalid env file (<file>): invalid utf8 bytes at line N: ...
} Prevention
- Save env files as UTF-8 without BOM (avoid PowerShell's UTF-16 default).
- Run 'file --mime-encoding <file>' expecting 'utf-8' in CI.
- Run 'iconv -f UTF-16 -t UTF-8' / 'dos2unix' on files from Windows.
When it happens
Trigger: An --env-file / --label-file (or compose env_file) saved in UTF-16/UTF-32, latin-1, Windows-1252, or containing a binary blob. A mid-file BOM also triggers it (only the line-1 BOM is stripped).
Common situations: Windows editors saving as 'Unicode' (UTF-16 LE), PowerShell Out-File defaulting to UTF-16, copy-pasting from a rich-text source introducing non-UTF-8 bytes, or committing a binary file as an env file.
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
- invalid env file ( )
- no variable name on line
- variable ' ' contains whitespaces
- every ip-range or gateway must have a corresponding subnet
- multiple overlapping subnet configuration is not supported
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/d24134b9d0070a9e.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/kvfile/kvfile.go:88
// 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}
for currentLine := 1; scanner.Scan(); currentLine++ {
scannedBytes := scanner.Bytes()
if !utf8.Valid(scannedBytes) {
return []string{}, fmt.Errorf("invalid utf8 bytes at line %d: %v", currentLine, scannedBytes)
}
// We trim UTF8 BOM
if currentLine == 1 {
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
}
// trim the line from all leading whitespace first. trailing whitespace
// is part of the value, and is kept unmodified.
line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
if len(line) == 0 || line[0] == '#' {
// skip empty lines and comments (lines starting with '#')
continue
}
key, _, hasValue := strings.Cut(line, "=")
if len(key) == 0 {
return []string{}, fmt.Errorf("no variable name on line '%s'", line)
}View on GitHub (pinned to 4f84911bfe)