{"record":{"id":"50bad3986066d5f4","repo":"twpayne/chezmoi","slug":"s-unknown-format","errorCode":null,"errorMessage":"%s: unknown format","messagePattern":"(.+?): unknown format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/chezmoi/format.go","lineNumber":72,"sourceCode":"\t}\n\n\t// FormatsByExtension is a map of all Formats by extension.\n\tFormatsByExtension = map[string]Format{\n\t\t\"jsonc\": FormatJSONC,\n\t\t\"json\":  FormatJSON,\n\t\t\"toml\":  FormatTOML,\n\t\t\"yaml\":  FormatYAML,\n\t\t\"yml\":   FormatYAML,\n\t}\n\tFormatExtensions = slices.Sorted(maps.Keys(FormatsByExtension))\n)\n\n// UnmarshalFileData unmarshals data in the format guessed from filenameAbsPath.\nfunc UnmarshalFileData(filenameAbsPath AbsPath, data []byte, value any) error {\n\textension := strings.TrimPrefix(filenameAbsPath.Ext(), \".\")\n\tformat, ok := FormatsByExtension[extension]\n\tif !ok {\n\t\treturn fmt.Errorf(\"%s: unknown format\", filenameAbsPath)\n\t}\n\treturn format.Unmarshal(data, value)\n}\n\n// Marshal implements Format.Marshal.\nfunc (formatJSONC) Marshal(value any) ([]byte, error) {\n\tvar builder strings.Builder\n\tencoder := json.NewEncoder(&builder)\n\tencoder.SetEscapeHTML(false)\n\tif err := encoder.Encode(value); err != nil {\n\t\treturn nil, err\n\t}\n\treturn hujson.Format([]byte(builder.String()))\n}\n\n// Name implements Format.Name.\nfunc (formatJSONC) Name() string {\n\treturn \"jsonc\"","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/twpayne/chezmoi/blob/f901167e4685db90da56d6a2a19df642cb3e0247/internal/chezmoi/format.go#L54-L90","documentation":"UnmarshalFileData guesses the serialization format from the file's extension (via FormatsByExtension) and unmarshals accordingly. If the extension has no registered format (e.g. .txt, .md, .unknown), it refuses to guess and reports the full filename. This prevents silently mis-parsing data with the wrong decoder.","triggerScenarios":"Calling UnmarshalFileData (directly or via newSourceState) on a source file whose extension is not one of the supported format extensions (json, jsonc, yaml, yml, toml).","commonSituations":"Adding a source file with an unusual extension, a dotfile like '.foo' whose trimmed extension is empty, renaming a config file to a non-format extension.","solutions":["Rename the file to use a supported extension (.json, .jsonc, .yaml, .yml, .toml)","Move non-format files out of the source state directory so they are not parsed","If the content is a supported format, fix the extension to match the actual content"],"exampleFix":"// before\nmv config.yaml myconfig.conf   # chezmoi cannot guess format\n\n// after\nmv config.yaml myconfig.yaml","handlingStrategy":"validation","validationCode":"supported := map[string]bool{\"json\":true,\"jsonc\":true,\"yaml\":true,\"yml\":true,\"toml\":true}\next := strings.TrimPrefix(filepath.Ext(path), \".\")\nif !supported[ext] { return fmt.Errorf(\"%s: no format for extension\", path) }","typeGuard":null,"tryCatchPattern":"if err := chezmoi.UnmarshalFileData(path, data, &v); err != nil {\n    if strings.Contains(err.Error(), \"unknown format\") {\n        // pick a format explicitly or skip the file\n    }\n}","preventionTips":["Keep source-state files limited to supported extensions","Never rename format files to arbitrary extensions","Separate non-format assets from files chezmoi parses"],"tags":["go","file-format","unmarshal","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"}