{"record":{"id":"bfa178f9680bd52e","repo":"gocolly/colly","slug":"invalid-slice-type","errorCode":null,"errorMessage":"Invalid slice type","messagePattern":"Invalid slice type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"unmarshal.go","lineNumber":177,"sourceCode":"\terr := UnmarshalHTML(v.Interface(), newS, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tattrV.Set(reflect.Indirect(v))\n\treturn nil\n}\n\nfunc unmarshalPtr(s *goquery.Selection, selector string, attrV reflect.Value) error {\n\tnewS := s\n\tif selector != \"\" {\n\t\tnewS = newS.Find(selector)\n\t}\n\tif newS.Nodes == nil {\n\t\treturn nil\n\t}\n\te := attrV.Type().Elem()\n\tif e.Kind() != reflect.Struct {\n\t\treturn errors.New(\"Invalid slice type\")\n\t}\n\tv := reflect.New(e)\n\terr := UnmarshalHTML(v.Interface(), newS, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tattrV.Set(v)\n\treturn nil\n}\n\nfunc unmarshalSlice(s *goquery.Selection, selector, htmlAttr string, attrV reflect.Value) error {\n\tif attrV.Pointer() == 0 {\n\t\tv := reflect.MakeSlice(attrV.Type(), 0, 0)\n\t\tattrV.Set(v)\n\t}\n\tswitch attrV.Type().Elem().Kind() {\n\tcase reflect.String:\n\t\ts.Find(selector).Each(func(_ int, s *goquery.Selection) {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/gocolly/colly/blob/17d1d6ca92bd32a5651f34256bf7a2855c967f65/unmarshal.go#L159-L195","documentation":"unmarshalPtr handles pointer fields; when the pointer's element type is a slice, the slice's element kind must be struct. If it is not (e.g. []*string, []int), it returns \"Invalid slice type\" (unmarshal.go:177). Only []*Struct slices under pointers are supported.","triggerScenarios":"A *[]*string / *[]int style field (or a *slice field whose Elem is not a struct) reached via unmarshalPtr from unmarshalSelector or unmarshalAttr during UnmarshalHTML.","commonSituations":"Declaring fields like Tags *[]string hoping for automatic string-list capture; refactoring []MyStruct to []string and keeping the selector tag.","solutions":["Make the slice element type a struct: *[]*Item with Item being a struct","Use []string only where supported paths allow it, or populate it manually after unmarshal","Remove the selector/attr tag from incompatible fields","Verify the Elem().Kind() of your slice fields equals reflect.Struct"],"exampleFix":"// before\ntype Page struct {\n  Links *[]string `selector:\"a\"`\n}\n// after\ntype Link struct { URL string `attr:\"href\"` }\ntype Page struct {\n  Links *[]*Link `selector:\"a\"`\n}","handlingStrategy":"validation","validationCode":"if f.Type.Kind() == reflect.Ptr {\n    e := f.Type.Elem()\n    if e.Kind() == reflect.Slice && e.Elem().Kind() != reflect.Struct {\n        panic(\"pointer-to-slice field must have struct elements\")\n    }\n}","typeGuard":"func validPtrSlice(f reflect.StructField) bool {\n    if f.Type.Kind() != reflect.Ptr { return true }\n    e := f.Type.Elem()\n    if e.Kind() != reflect.Slice { return true }\n    return e.Elem().Kind() == reflect.Struct\n}","tryCatchPattern":"if err := colly.UnmarshalHTML(&result, sel, nil); err != nil {\n    if err.Error() == \"Invalid slice type\" {\n        log.Printf(\"slice element must be struct: %v\", err)\n    }\n    return err\n}","preventionTips":["Use []*Struct (or []Struct) for repeated DOM nodes under pointers","Avoid *[]string / *[]int tagged fields entirely","Test unmarshaling against a small HTML fixture in CI","Keep tagged schemas limited to struct-carrying types"],"tags":["reflection","unmarshal","slices","go"],"backgroundTag":"unsupported-field-type","analyzedSha":"17d1d6ca92bd32a5651f34256bf7a2855c967f65","analyzedAt":"2026-08-30T21:32:31.579Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}