gocolly/colly · error
Invalid slice type
Error message
Invalid slice type
What it means
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.
Source
Thrown at unmarshal.go:177
err := UnmarshalHTML(v.Interface(), newS, nil)
if err != nil {
return err
}
attrV.Set(reflect.Indirect(v))
return nil
}
func unmarshalPtr(s *goquery.Selection, selector string, attrV reflect.Value) error {
newS := s
if selector != "" {
newS = newS.Find(selector)
}
if newS.Nodes == nil {
return nil
}
e := attrV.Type().Elem()
if e.Kind() != reflect.Struct {
return errors.New("Invalid slice type")
}
v := reflect.New(e)
err := UnmarshalHTML(v.Interface(), newS, nil)
if err != nil {
return err
}
attrV.Set(v)
return nil
}
func unmarshalSlice(s *goquery.Selection, selector, htmlAttr string, attrV reflect.Value) error {
if attrV.Pointer() == 0 {
v := reflect.MakeSlice(attrV.Type(), 0, 0)
attrV.Set(v)
}
switch attrV.Type().Elem().Kind() {
case reflect.String:
s.Find(selector).Each(func(_ int, s *goquery.Selection) {View on GitHub (pinned to 17d1d6ca92)
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
Example fix
// before
type Page struct {
Links *[]string `selector:"a"`
}
// after
type Link struct { URL string `attr:"href"` }
type Page struct {
Links *[]*Link `selector:"a"`
} Defensive patterns
Strategy: validation
Validate before calling
if f.Type.Kind() == reflect.Ptr {
e := f.Type.Elem()
if e.Kind() == reflect.Slice && e.Elem().Kind() != reflect.Struct {
panic("pointer-to-slice field must have struct elements")
}
} Type guard
func validPtrSlice(f reflect.StructField) bool {
if f.Type.Kind() != reflect.Ptr { return true }
e := f.Type.Elem()
if e.Kind() != reflect.Slice { return true }
return e.Elem().Kind() == reflect.Struct
} Try / catch
if err := colly.UnmarshalHTML(&result, sel, nil); err != nil {
if err.Error() == "Invalid slice type" {
log.Printf("slice element must be struct: %v", err)
}
return err
} Prevention
- 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
When it happens
Trigger: A *[]*string / *[]int style field (or a *slice field whose Elem is not a struct) reached via unmarshalPtr from unmarshalSelector or unmarshalAttr during UnmarshalHTML.
Common situations: Declaring fields like Tags *[]string hoping for automatic string-list capture; refactoring []MyStruct to []string and keeping the selector tag.
Related errors
AI-assisted analysis of gocolly/colly@17d1d6ca92 (2026-08-30).
Data as JSON: /api/errors/bfa178f9680bd52e.
Report an issue: GitHub.