AlexxIT/go2rtc · warning
tlv8: zero item
Error message
tlv8: zero item
What it means
A TLV8 record with length byte L == 0 carries no value; the library treats this as a non-critical condition: it skips the 2-byte header (returning b[2:], so decoding continues) but still reports "tlv8: zero item". Callers like unmarshalStruct ignore the error and keep looping; unmarshalSlice uses the non-nil remaining bytes to advance to the next array element. It typically signals a separator/empty record or a struct field encoded with length 0.
Solutions
- No action needed if fields are intentionally empty: the library skips L=0 records and continues; treat this as informational.
- If the missing value matters, validate after decoding that the expected struct fields are non-zero before using the result.
- If you control the encoder, encode empty values with the correct tag/length rather than bare tag,0x00 records.
- Confirm the payload source matches the expected TLV8 schema (tags and field order) — a zero item where data is expected usually means wrong payload type.
Example fix
// before
tlv8.Unmarshal(data, &resp) // assume all fields populated
usePairing(resp.Identifier) // Identifier empty -> zero item was skipped
// after
tlv8.Unmarshal(data, &resp)
if len(resp.Identifier) == 0 {
return errors.New("peer sent empty identifier (tlv8 zero item)")
} Defensive patterns
Strategy: validation
Validate before calling
// after decoding, verify required fields were populated
if err := tlv8.Unmarshal(data, &resp); err != nil {
return err
}
if resp.Identifier == nil || len(resp.Identifier) == 0 {
return errors.New("required tlv8 field 1 (identifier) missing or empty")
} Try / catch
// zero item is non-critical: the library skips it, so validate results afterwards
if err := tlv8.Unmarshal(data, &resp); err != nil {
return err
}
if reflect.ValueOf(resp).IsZero() {
return errors.New("tlv8 payload decoded to empty result (zero items only)")
} Prevention
- Treat L=0 records as 'field absent' and always validate required fields after Unmarshal.
- When interoperating with other TLV8 implementations, agree on how empty values are encoded.
- Distinguish array separators (0xFF,0x00) from genuine zero-length values when inspecting raw payloads.
- Add unit tests with empty-field payloads so downstream code handles them explicitly.
When it happens
Trigger: Any Unmarshal call whose payload contains a record with L=0 — e.g. a field encoded as tag,0x00 with no value (often an empty struct tag written by appendValue as tag,0x00), or a 0xFF,0x00 array separator — decoded through unmarshalTLV from unmarshalSlice/unmarshalStruct.
Common situations: Empty optional fields in HAP pairing payloads (e.g. zero-length identifiers); payloads produced by other TLV8 implementations that encode empty values as L=0; separators between array items misread as zero-length records; decoding data from a non-Go peer with different empty-value conventions.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- tlv8: unmarshal zero data
- tlv8: value should be pointer:
- tlv8: wrong size:
- tlv8: can't find T= ,L= ,V= for
- hap: wrong request: %#v
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/740495cc4fc668db.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/hap/tlv8/tlv8.go:237
}
return errors.New("tlv8: not implemented: " + kind.String())
}
// unmarshalTLV can return two types of errors:
// - critical and then the value of []byte will be nil
// - not critical and then []byte will contain the value
func unmarshalTLV(b []byte, value reflect.Value) ([]byte, error) {
if len(b) < 2 {
return nil, errors.New("tlv8: wrong size: " + value.Type().Name())
}
t := b[0]
l := int(b[1])
// array item divider (t == 0x00 || t == 0xFF)
if l == 0 {
return b[2:], errors.New("tlv8: zero item")
}
var v []byte
for {
if len(b) < 2+l {
return nil, errors.New("tlv8: wrong size: " + value.Type().Name())
}
v = append(v, b[2:2+l]...)
b = b[2+l:]
// if size == 255 and same tag - continue read big payload
if l < 255 || len(b) < 2 || b[0] != t {
break
}
l = int(b[1])View on GitHub (pinned to c245815e75)