{"record":{"id":"1f74737e58bdfcb8","repo":"twpayne/chezmoi","slug":"expected-a-string-got-a-t-element","errorCode":null,"errorMessage":"expected a []string, got a %T element","messagePattern":"expected a \\[\\]string, got a %T element","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/chezmoi/entrytypeset.go","lineNumber":361,"sourceCode":"}\n\n// StringSliceToEntryTypeSetHookFunc is a\n// github.com/go-viper/mapstructure/v2.DecodeHookFunc that parses an\n// EntryTypeSet from a []string.\nfunc StringSliceToEntryTypeSetHookFunc() mapstructure.DecodeHookFunc {\n\treturn func(from, to reflect.Type, data any) (any, error) {\n\t\tif to != reflect.TypeFor[EntryTypeSet]() {\n\t\t\treturn data, nil\n\t\t}\n\t\telemsAny, ok := data.([]any)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"expected a []string, got a %T\", data)\n\t\t}\n\t\telemStrs := make([]string, len(elemsAny))\n\t\tfor i, elemAny := range elemsAny {\n\t\t\telemStr, ok := elemAny.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"expected a []string, got a %T element\", elemAny)\n\t\t\t}\n\t\t\telemStrs[i] = elemStr\n\t\t}\n\t\ts := NewEntryTypeSet(EntryTypesNone)\n\t\tif err := s.SetSlice(elemStrs); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn s, nil\n\t}\n}\n\n// EntryTypeSetFlagCompletionFunc completes EntryTypeSet flags.\nfunc EntryTypeSetFlagCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\tvar completions []string\n\tentryTypes := strings.Split(toComplete, \",\")\n\tlastEntryType := entryTypes[len(entryTypes)-1]\n\tvar prefix string\n\tif len(entryTypes) > 0 {","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/twpayne/chezmoi/blob/f901167e4685db90da56d6a2a19df642cb3e0247/internal/chezmoi/entrytypeset.go#L343-L379","documentation":"Same decode hook as the array-level check, but this fires per element: the data was a []any, yet one of its elements is not a string. The error reports the element's actual Go type so the offending config value can be identified.","triggerScenarios":"An entry type list contains a non-string element, e.g. mode = [123], [true], or a nested list [[\"file\"]] resulting from YAML/JSON parsing.","commonSituations":"Unquoted numeric-looking type values in TOML/YAML, accidental nesting of lists, template or script generating config with wrong element types.","solutions":["Quote the element so it parses as a string (e.g. [\"file\"] not [file] where file resolves oddly)","Flatten accidental nested lists","Inspect the reported %T type to locate the bad element and correct it"],"exampleFix":"// before\nmode = [file, dir]\n\n// after\nmode = [\"file\", \"dir\"]","handlingStrategy":"type-guard","validationCode":"for i, e := range elems {\n    if _, ok := e.(string); !ok {\n        return fmt.Errorf(\"element %d is %T, want string\", i, e)\n    }\n}","typeGuard":"func isStringElem(v any) bool {\n    _, ok := v.(string)\n    return ok\n}","tryCatchPattern":"if err := decode(data, &out); err != nil {\n    if strings.Contains(err.Error(), \"got a %T element\") || strings.Contains(err.Error(), \" element\") {\n        // coerce numeric/bool elements to strings and retry\n    }\n}","preventionTips":["Quote list elements in config so parsers yield strings","Avoid nested lists in entry-type fields","Run config through a linter/schema check before feeding to decode hooks"],"tags":["go","type-mismatch","decode-hook","configuration"],"backgroundTag":"expected-array-of-strings","analyzedSha":"f901167e4685db90da56d6a2a19df642cb3e0247","analyzedAt":"2026-09-01T18:16:41.508Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}