gocolly/colly · error

Invalid type or nil-pointer

Error message

Invalid type or nil-pointer

What it means

UnmarshalHTML requires its first argument to be a non-nil pointer to the struct being populated. If v is not a pointer or is a nil pointer, it returns "Invalid type or nil-pointer" (unmarshal.go:55) via reflection checks on reflect.ValueOf(v).

Source

Thrown at unmarshal.go:55

// Allowed struct tags:
//   - "selector" (required): CSS (goquery) selector of the desired data
//   - "attr" (optional): Selects the matching element's attribute's value.
//     Leave it blank or omit to get the text of the element.
//
// Example struct declaration:
//
//	type Nested struct {
//		String  string   `selector:"div > p"`
//	   Classes []string `selector:"li" attr:"class"`
//		Struct  *Nested  `selector:"div > div"`
//	}
//
// Supported types: struct, *struct, string, []string
func UnmarshalHTML(v interface{}, s *goquery.Selection, structMap map[string]string) error {
	rv := reflect.ValueOf(v)

	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return errors.New("Invalid type or nil-pointer")
	}

	sv := rv.Elem()
	st := reflect.TypeOf(v).Elem()
	if structMap != nil {
		for k, v := range structMap {
			attrV := sv.FieldByName(k)
			if !attrV.CanAddr() || !attrV.CanSet() {
				continue
			}
			if err := unmarshalSelector(s, attrV, v); err != nil {
				return err
			}
		}
	} else {
		for i := 0; i < sv.NumField(); i++ {
			attrV := sv.Field(i)
			if !attrV.CanAddr() || !attrV.CanSet() {

View on GitHub (pinned to 17d1d6ca92)

Solutions

  1. Pass a pointer to your struct: UnmarshalHTML(&result, sel, nil)
  2. Initialize the pointer before the call (result := &MyStruct{})
  3. Check the argument's type at the call site; only *struct is accepted
  4. Handle the returned error to catch programming mistakes early

Example fix

// before
var s MyStruct
colly.UnmarshalHTML(s, sel, nil)
// after
s := &MyStruct{}
err := colly.UnmarshalHTML(s, sel, nil)
Defensive patterns

Strategy: validation

Validate before calling

if v == nil || reflect.ValueOf(v).Kind() != reflect.Ptr || reflect.ValueOf(v).IsNil() {
    return fmt.Errorf("UnmarshalHTML needs a non-nil struct pointer")
}

Type guard

func isUnmarshalTarget(v interface{}) bool {
    rv := reflect.ValueOf(v)
    return rv.Kind() == reflect.Ptr && !rv.IsNil() && rv.Elem().Kind() == reflect.Struct
}

Try / catch

if err := colly.UnmarshalHTML(&result, sel, nil); err != nil {
    if err.Error() == "Invalid type or nil-pointer" {
        log.Println("check argument: must be non-nil *struct")
    }
    return err
}

Prevention

When it happens

Trigger: Calling colly.UnmarshalHTML with a struct value instead of &struct, or with a nil pointer variable; also propagated when nested UnmarshalHTML calls receive non-pointer elements.

Common situations: Passing MyStruct{} instead of &MyStruct{}; a typed nil (*MyStruct)(nil); map/slice elements that are values not pointers; misusing the API after switching from Unmarshal to UnmarshalHTML.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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