{"record":{"id":"e23b45466c12f40c","repo":"twpayne/chezmoi","slug":"s-w-e23b45","errorCode":null,"errorMessage":"%s: %w","messagePattern":"%s: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/chezmoi/format.go","lineNumber":196,"sourceCode":"\tdecoder := yaml.NewDecoder(\n\t\tbytes.NewReader(data),\n\t\tyaml.DisallowUnknownField(),\n\t)\n\tswitch err := decoder.Decode(value); {\n\tcase errors.Is(err, io.EOF):\n\t\treturn nil // Empty input is OK.\n\tcase err != nil:\n\t\treturn err\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// FormatFromAbsPath returns the expected format of absPath.\nfunc FormatFromAbsPath(absPath AbsPath) (Format, error) {\n\tformat, err := formatFromExtension(absPath.Ext())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s: %w\", absPath, err)\n\t}\n\treturn format, nil\n}\n\n// formatFromExtension returns the expected format of absPath.\nfunc formatFromExtension(extension string) (Format, error) {\n\tformat, ok := FormatsByExtension[strings.TrimPrefix(extension, \".\")]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%s: unknown format\", extension)\n\t}\n\treturn format, nil\n}\n\nfunc isPrefixDotFormat(name, prefix string) bool {\n\tfor extension := range FormatsByExtension {\n\t\tif name == prefix+\".\"+extension {\n\t\t\treturn true\n\t\t}","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/twpayne/chezmoi/blob/f901167e4685db90da56d6a2a19df642cb3e0247/internal/chezmoi/format.go#L178-L214","documentation":"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'.","triggerScenarios":"Calling FormatFromAbsPath (from addExternal, addTemplateData, decodeConfigFile, persistentPostRunRootE) with a file whose extension is not registered in FormatsByExtension.","commonSituations":"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.","solutions":["Use a supported extension for the file (.json/.jsonc/.yaml/.yml/.toml)","Specify the format explicitly where the API allows instead of relying on extension inference","Correct the path passed to FormatFromAbsPath if it points at the wrong file"],"exampleFix":"// before\nformat, err := chezmoi.FormatFromAbsPath(chezmoi.NewAbsPath(\"/home/u/.secrets.txt\"))\n\n// after\nformat, err := chezmoi.FormatFromAbsPath(chezmoi.NewAbsPath(\"/home/u/.secrets.yaml\"))","handlingStrategy":"validation","validationCode":"ext := strings.TrimPrefix(filepath.Ext(absPath.String()), \".\")\nswitch ext {\ncase \"json\", \"jsonc\", \"yaml\", \"yml\", \"toml\":\n    // ok\ndefault:\n    return fmt.Errorf(\"%s has unsupported format extension\", absPath)\n}","typeGuard":null,"tryCatchPattern":"format, err := chezmoi.FormatFromAbsPath(p)\nif err != nil {\n    // err is wrapped; check for 'unknown format' inside and choose a default\n    return fmt.Errorf(\"cannot infer format: %w\", err)\n}","preventionTips":["Verify file extensions before calling format inference APIs","Use explicit format parameters where available","Standardize on lowercase canonical extensions in tooling"],"tags":["go","file-format","extension","configuration"],"backgroundTag":"unknown-file-format","analyzedSha":"f901167e4685db90da56d6a2a19df642cb3e0247","analyzedAt":"2026-09-01T18:16:41.508Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}