gocolly/colly · error

Invalid type:

Error message

Invalid type: 

What it means

unmarshalSelector maps a struct field tagged with `selector` to part of the DOM. It supports struct, slice, and pointer field kinds; any other kind (string, int, etc.) reaches the default branch and returns "Invalid type: <value>" (unmarshal.go:115). The value's kind is not a supported selector target.

Source

Thrown at unmarshal.go:115

		}
	case reflect.String:
		var val string
		if selector == "" && htmlAttr != "" {
			val = getDOMValue(s, htmlAttr)
		} else {
			val = getDOMValue(s.Find(selector), htmlAttr)
		}
		attrV.Set(reflect.Indirect(reflect.ValueOf(val)))
	case reflect.Struct:
		if err := unmarshalStruct(s, selector, attrV); err != nil {
			return err
		}
	case reflect.Ptr:
		if err := unmarshalPtr(s, selector, attrV); err != nil {
			return err
		}
	default:
		return errors.New("Invalid type: " + attrV.String())
	}
	return nil
}

func unmarshalAttr(s *goquery.Selection, attrV reflect.Value, attrT reflect.StructField) error {
	selector := attrT.Tag.Get("selector")
	//selector is "-" specify that field should ignore.
	if selector == "-" {
		return nil
	}
	htmlAttr := attrT.Tag.Get("attr")
	// TODO support more types
	switch attrV.Kind() {
	case reflect.Slice:
		if err := unmarshalSlice(s, selector, htmlAttr, attrV); err != nil {
			return err
		}
	case reflect.String:

View on GitHub (pinned to 17d1d6ca92)

Solutions

  1. Change the field type to a struct, *struct, or slice of structs
  2. Move the selector tag to the struct level (on the struct type passed to UnmarshalHTML) for scalar capture via `map` tags or use `attr`-style handling
  3. Remove the selector tag if the field is not meant for DOM binding
  4. Check field kinds against the supported list in unmarshal.go

Example fix

// before
type Item struct {
  Title string `selector:"h1"`
}
// after
type Title struct {
  Text string `selector:"h1"`
}
type Item struct {
  Title Title `selector:""`
}
Defensive patterns

Strategy: validation

Validate before calling

// before unmarshaling, verify selector-tagged fields are struct/slice/pointer kinds
for _, f := range reflect.VisibleFields(reflect.TypeOf(Item{})) {
    if f.Tag.Get("selector") != "" {
        k := f.Type.Kind()
        if k != reflect.Struct && k != reflect.Slice && k != reflect.Ptr {
            panic("field " + f.Name + " has selector tag but unsupported kind")
        }
    }
}

Try / catch

if err := colly.UnmarshalHTML(&result, sel, nil); err != nil {
    if strings.HasPrefix(err.Error(), "Invalid type:") {
        log.Printf("schema error: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Declaring a struct field with a `selector:"..."` tag whose type is not struct, []struct, or *struct — e.g. a plain string field with a selector tag — then calling UnmarshalHTML/Unmarshal.

Common situations: Assuming `selector` tags work on scalar fields like strings; copying tags from struct-level examples onto primitive fields; schema drift after refactoring field types.

Related errors


AI-assisted analysis of gocolly/colly@17d1d6ca92 (2026-08-30). Data as JSON: /api/errors/3c6b2b915d43a0d5. Report an issue: GitHub.