twpayne/chezmoi · error

%s: parse error

Error message

%s: parse error

What it means

parseOSRelease reads an /etc/os-release style file into a key/value map. Every non-comment, non-empty line must contain an '=' separating key and value; a line without '=' causes this error, reported with the offending line content. It signals a malformed or non-os-release file being parsed.

Source

Thrown at internal/chezmoi/data.go:91

func maybeUnquote(s string) string {
	if unquotedS, err := unquote(s); err == nil {
		return unquotedS
	}
	return s
}

// parseOSRelease parses operating system identification data from r as defined
// by the os-release specification.
func parseOSRelease(data []byte) (map[string]any, error) {
	result := make(map[string]any)
	for line := range bytes.Lines(data) {
		token := bytes.TrimSpace(line)
		if len(token) == 0 || token[0] == '#' {
			continue
		}
		key, value, ok := bytes.Cut(token, []byte{'='})
		if !ok {
			return nil, fmt.Errorf("%s: parse error", token)
		}
		result[string(key)] = maybeUnquote(string(value))
	}
	return result, nil
}

func unquote(s string) (string, error) {
	switch {
	case len(s) < 2:
		fallthrough
	case s[0] != '"' && s[0] != '\'':
		fallthrough
	case s[0] != s[len(s)-1]:
		return "", strconv.ErrSyntax
	case strings.IndexByte(s, '\\') == -1:
		return s[1 : len(s)-1], nil
	}
	bs := []byte(s[1 : len(s)-1])

View on GitHub (pinned to f901167e46)

Solutions

  1. Inspect the os-release file being parsed and fix the malformed line to key=value form
  2. Restore the stock /etc/os-release from the distro package (e.g. reinstall the base-files/os-release package)
  3. If a custom file is being fed in, correct or remove the offending line

Example fix

// before: broken os-release line
NAME="Debian GNU/Linux"
Debian 12

// after
NAME="Debian GNU/Linux"
VERSION="12 (bookworm)"
Defensive patterns

Strategy: validation

Validate before calling

for i, line := range bytes.Split(data, []byte{'\n'}) {
    line = bytes.TrimSpace(line)
    if len(line) == 0 || line[0] == '#' { continue }
    if !bytes.Contains(line, []byte{'='}) {
        return fmt.Errorf("line %d has no '=': %q", i+1, line)
    }
}

Try / catch

osRelease, err := OSRelease()
if err != nil && strings.HasSuffix(err.Error(), "parse error") {
    // treat as unknown OS / use fallback detection
}

Prevention

When it happens

Trigger: Calling OSRelease (or the anonymous caller) on a file whose content has a line without 'key=value' form — e.g. a custom os-release override missing '=', stray prose, or CRLF/binary garbage.

Common situations: Pointing chezmoi at a wrong file for OS release detection, a customized /etc/os-release broken by manual edits, container images shipping a stub os-release with junk lines.

Understand the failure class

Related errors


AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01). Data as JSON: /api/errors/69e872331b8da567. Report an issue: GitHub.