AlexxIT/go2rtc · error

tlv8: value should be pointer:

Error message

tlv8: value should be pointer: 

What it means

tlv8.Unmarshal requires its output parameter `v` to be a pointer so it can write decoded fields into the caller's value via reflection. When `v` is passed by value (e.g. a struct or map, not `&struct`), reflect.ValueOf(v).Kind() is not reflect.Pointer and this error is returned before any decoding happens. The kind that was actually received is appended to the message to help identify the mistake.

Solutions

  1. Pass a pointer to the destination: tlv8.Unmarshal(data, &out) instead of tlv8.Unmarshal(data, out).
  2. If the value is held in an interface variable, store a pointer in it: var out any = &MyStruct{} before calling Unmarshal.
  3. If you only have a reflect.Value, verify rv.Kind() == reflect.Pointer && !rv.IsNil() before calling Unmarshal.
  4. Check wrapper call sites (Dial, Pair, PairSetup, PairVerify, UnmarshalBase64, UnmarshalReader) and confirm the out argument you supply to them is addressable.

Example fix

// before
var resp pairVerifyResponse
tlv8.Unmarshal(data, resp)

// after
var resp pairVerifyResponse
tlv8.Unmarshal(data, &resp)
Defensive patterns

Strategy: type-guard

Validate before calling

// before calling
data, err := base64.StdEncoding.DecodeString(in)
if err != nil || len(data) == 0 {
    return err
}
// ensure out is a non-nil pointer to struct/slice
rv := reflect.ValueOf(out)
if rv.Kind() != reflect.Pointer || rv.IsNil() {
    return errors.New("out must be a non-nil pointer")
}

Type guard

func isDecodableTarget(v any) bool {
    rv := reflect.ValueOf(v)
    if rv.Kind() != reflect.Pointer || rv.IsNil() {
        return false
    }
    k := rv.Elem().Kind()
    return k == reflect.Struct || k == reflect.Slice
}

Try / catch

// Go: handle the returned error, there is no panic
if err := tlv8.UnmarshalBase64(in, &out); err != nil {
    if strings.HasPrefix(err.Error(), "tlv8: value should be pointer") {
        return fmt.Errorf("bad unmarshal target: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling tlv8.Unmarshal(data, out), tlv8.UnmarshalBase64(in, out), or tlv8.UnmarshalReader(r, n, out) — and transitively the HAP client methods Dial, Pair, PairSetup, PairVerify — with a non-pointer `out` argument, such as Unmarshal(data, structValue) instead of Unmarshal(data, &structValue).

Common situations: Declaring the destination struct but forgetting the `&` when calling Unmarshal/UnmarshalBase64; passing an interface variable that wraps a non-pointer; copying a helper that accepted **T and calling it with T; intermediate variables like `var out MyStruct` passed directly in multi-return calls.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/68b19886acece36e. Report an issue: GitHub.

Appendix: source

Thrown at pkg/hap/tlv8/tlv8.go:203

		data, err = io.ReadAll(r)
	}
	if err != nil {
		return err
	}

	return Unmarshal(data, v)
}

func Unmarshal(data []byte, v any) error {
	if len(data) == 0 {
		return errors.New("tlv8: unmarshal zero data")
	}

	value := reflect.ValueOf(v)
	kind := value.Kind()

	if kind != reflect.Pointer {
		return errors.New("tlv8: value should be pointer: " + kind.String())
	}

	value = value.Elem()
	kind = value.Kind()

	if kind == reflect.Interface {
		value = value.Elem()
		kind = value.Kind()
	}

	switch kind {
	case reflect.Slice:
		return unmarshalSlice(data, value)
	case reflect.Struct:
		return unmarshalStruct(data, value)
	}

	return errors.New("tlv8: not implemented: " + kind.String())

View on GitHub (pinned to c245815e75)