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

  1. Make the slice element type a struct: *[]*Item with Item being a struct
  2. Use []string only where supported paths allow it, or populate it manually after unmarshal
  3. Remove the selector/attr tag from incompatible fields
  4. 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

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.