twpayne/chezmoi · error

%s: %w

Error message

%s: %w

What it means

FormatFromAbsPath determines the Format for a file from its extension via formatFromExtension and wraps any failure with the full absolute path for context. The underlying cause is almost always the 'unknown format' error from the extension lookup, so the final message reads '<path>: <ext>: unknown format'.

Source

Thrown at internal/chezmoi/format.go:196

	decoder := yaml.NewDecoder(
		bytes.NewReader(data),
		yaml.DisallowUnknownField(),
	)
	switch err := decoder.Decode(value); {
	case errors.Is(err, io.EOF):
		return nil // Empty input is OK.
	case err != nil:
		return err
	default:
		return nil
	}
}

// FormatFromAbsPath returns the expected format of absPath.
func FormatFromAbsPath(absPath AbsPath) (Format, error) {
	format, err := formatFromExtension(absPath.Ext())
	if err != nil {
		return nil, fmt.Errorf("%s: %w", absPath, err)
	}
	return format, nil
}

// formatFromExtension returns the expected format of absPath.
func formatFromExtension(extension string) (Format, error) {
	format, ok := FormatsByExtension[strings.TrimPrefix(extension, ".")]
	if !ok {
		return nil, fmt.Errorf("%s: unknown format", extension)
	}
	return format, nil
}

func isPrefixDotFormat(name, prefix string) bool {
	for extension := range FormatsByExtension {
		if name == prefix+"."+extension {
			return true
		}

View on GitHub (pinned to f901167e46)

Solutions

  1. Use a supported extension for the file (.json/.jsonc/.yaml/.yml/.toml)
  2. Specify the format explicitly where the API allows instead of relying on extension inference
  3. Correct the path passed to FormatFromAbsPath if it points at the wrong file

Example fix

// before
format, err := chezmoi.FormatFromAbsPath(chezmoi.NewAbsPath("/home/u/.secrets.txt"))

// after
format, err := chezmoi.FormatFromAbsPath(chezmoi.NewAbsPath("/home/u/.secrets.yaml"))
Defensive patterns

Strategy: validation

Validate before calling

ext := strings.TrimPrefix(filepath.Ext(absPath.String()), ".")
switch ext {
case "json", "jsonc", "yaml", "yml", "toml":
    // ok
default:
    return fmt.Errorf("%s has unsupported format extension", absPath)
}

Try / catch

format, err := chezmoi.FormatFromAbsPath(p)
if err != nil {
    // err is wrapped; check for 'unknown format' inside and choose a default
    return fmt.Errorf("cannot infer format: %w", err)
}

Prevention

When it happens

Trigger: Calling FormatFromAbsPath (from addExternal, addTemplateData, decodeConfigFile, persistentPostRunRootE) with a file whose extension is not registered in FormatsByExtension.

Common situations: chezmoi add or chezmoi init on a file with a non-format extension, a config file path typo'd extension, archive/external files with exotic extensions.

Related errors


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