{"record":{"id":"0fed5c1893f4cc36","repo":"gohugoio/hugo","slug":"cannot-unmarshal-csv-into-t","errorCode":null,"errorMessage":"cannot unmarshal CSV into %T","messagePattern":"cannot unmarshal CSV into %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"parser/metadecoders/decoder.go","lineNumber":377,"sourceCode":"\t\t\t\tseen[fieldName] = true\n\t\t\t}\n\n\t\t\tsm := make([]map[string]string, len(records)-1)\n\t\t\tfor i, record := range records[1:] {\n\t\t\t\tm := make(map[string]string, len(records[0]))\n\t\t\t\tfor j, col := range record {\n\t\t\t\t\tm[records[0][j]] = col\n\t\t\t\t}\n\t\t\t\tsm[i] = m\n\t\t\t}\n\t\t\t*vv = sm\n\t\tcase \"slice\":\n\t\t\t*vv = records\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"cannot unmarshal CSV into %T: invalid targetType: expected either slice or map, received %s\", v, d.TargetType)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"cannot unmarshal CSV into %T\", v)\n\t}\n\n\treturn nil\n}\n\nfunc parseORGDate(s string) string {\n\tr := regexp.MustCompile(`[<\\[](\\d{4}-\\d{2}-\\d{2}) .*[>\\]]`)\n\tif m := r.FindStringSubmatch(s); m != nil {\n\t\treturn m[1]\n\t}\n\treturn s\n}\n\nfunc (d Decoder) unmarshalORG(data []byte, v any) error {\n\tconfig := org.New()\n\tconfig.Log = log.Default() // TODO(bep)\n\tdocument := config.Parse(bytes.NewReader(data), \"\")\n\tif document.Error != nil {","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/parser/metadecoders/decoder.go#L359-L395","documentation":"Thrown by Decoder.unmarshalCSV (parser/metadecoders/decoder.go:377) in the default branch of the type switch when the target 'v' is not *interface{} (*any). The CSV decoder only knows how to populate a generic any (which it then sets to either a [][]string for slice mode or []map[string]string for map mode); passing a typed pointer like *[][]string or *MyStruct hits the default branch. The %T names the unsupported destination type.","triggerScenarios":"Calling UnmarshalTo/Unmarshal for CSV with v = &rows where rows is [][]string, or v = &myStruct; programmatic misuse expecting reflection-based typed decoding that the CSV path does not support.","commonSituations":"Theme/plugin authors calling the metadecoders CSV path with a concrete typed destination; assuming CSV decodes into typed structs like JSON/TOML do.","solutions":["Decode CSV into a *interface{} (var v any; dec.UnmarshalTo(data, metadecoders.CSV, &v)) then type-assert the result.","For slice mode the result is [][]string; for map mode it is []map[string]string — assert accordingly.","Use encoding/csv directly if you need a typed reader."],"exampleFix":"// before\nvar rows [][]string\nerr := dec.UnmarshalTo(data, metadecoders.CSV, &rows)\n\n// after\nvar v any\nerr := dec.UnmarshalTo(data, metadecoders.CSV, &v)\nrows := v.([][]string)","handlingStrategy":"type-guard","validationCode":"// CSV decoder only accepts *interface{}.\nfunc isAnyPointer(v any) bool {\n    _, ok := v.(*any)\n    return ok\n}","typeGuard":"func isCSVTarget(v any) bool {\n    _, ok := v.(*any)\n    return ok\n}","tryCatchPattern":"var v any\nif err := dec.UnmarshalTo(data, metadecoders.CSV, &v); err != nil {\n    return fmt.Errorf(\"CSV decode: %w\", err)\n}\n// type-assert: v.([][]string) or v.([]map[string]string)","preventionTips":["Always decode CSV into *interface{} then type-assert the result.","Use encoding/csv directly for typed/struct decoding.","Remember CSV never populates typed structs."],"tags":["csv","metadecoders","type-mismatch","api-misuse","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}