ErrLookupBackground articles › "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained

"cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained

Protobuf unmarshal errors appear when bytes passed to a protobuf decoder (proto.Unmarshal, protoutil.Unmarshal, easyproto, gogo/protobuf) are not a valid encoding of the expected message — corrupted, truncated, empty, or produced from a different schema. Developers hit them as messages like "cannot unmarshal point", "failed unmarshalling payload", "error unmarshalling Envelope", "illegal tag", or "wiretype end group for non-group" from libraries such as VictoriaMetrics, Hyperledger Fabric, Teleport, rqlite, and Pulumi.

Distilled from 144 documented records across 10 repositories.

Background

This error family lives at the boundary between raw bytes and structured data. Every protobuf library — google.golang.org/protobuf, gogo/protobuf, easyproto, protoutil wrappers — walks the wire format one field at a time: it reads a tag varint (field number plus wire type), then the payload for that wire type. The decoder fails the moment the stream stops making sense: a tag with wire type 4 (end-group) where no group was opened (Teleport's "wiretype end group for non-group" on the Passwordless message), a field number <= 0 or an unknown field whose skip logic also fails ("illegal tag %d (wire type %d)"), a length-delimited field whose length exceeds the remaining bytes, or a nested MessageData() call that cannot extract the declared submessage (VictoriaMetrics' easyproto-based "cannot read Sketch data"). The decoder has no schema knowledge beyond the message it is filling, so any deviation from valid wire format — not just a wrong field value — is fatal.

Critically, the wire format is untyped at the top: the decoder fills whatever message struct you hand it. That means these errors usually do not mean "bad field value"; they mean the bytes were never a serialization of the expected message at all. The recurring patterns across the records are: (1) truncation — a request cut off mid-frame by a proxy, a Content-Length mismatch, a partial TCP read, or a truncated block on disk (Fabric's "error unmarshalling Envelope" from block Data, rqlite's "protobuf unmarshal" on the cluster mux); (2) wrong bytes entirely — an HTTP 200 body that is actually HTML or JSON being decoded as protobuf (7days-golang's "decoding response body"), gzip or snappy not decompressed before decoding, base64 still applied, or bytes of a different message type placed in a slot (a SignatureHeader marshaled into a ChannelHeader slot, an Idemix MSPConfig passed to a FABRIC-type MSP); and (3) schema or version skew between producer and consumer — sender and receiver built from different .proto definitions, so field numbers or shapes diverge (rqlite nodes on incompatible versions, Fabric SDKs and peers on mismatched fabric-protos).

From the caller's side the error usually arrives wrapped: the library adds context about which decode step failed and which message was expected, while the underlying cause carries the protobuf-level detail. Some wrappers include the payload size (VictoriaMetrics' prompb WriteRequest error reports the byte count, which immediately distinguishes an empty body from a huge truncated one); others include a transaction ID (Fabric's "failed to unmarshal response for transaction %s"); others use a %w chain the caller must unwrap to see the real cause. Fabric alone contributes a dozen variants, each naming the exact message that failed to decode — Envelope, Payload, Proposal, ChannelHeader, MSPRole, MSPConfig, CollectionConfigPackage, ChaincodeData — because its architecture unmarshals protobuf at many trust boundaries (block parsing, transaction validation, policy evaluation, MSP setup, discovery), so corruption at any boundary produces a distinct message but the same root mechanism.

A few behaviors are library-specific. VictoriaMetrics uses hand-rolled easyproto decoding, so it fails early and precisely at each field ("cannot read next field in Sketch message") and expects callers to check wire types (field 1 must be wire type 2, length-delimited). Fabric's *OrPanic variants (UnmarshalConfigOrPanic) panic instead of returning an error, treating decode failure as a programmer error or corrupted internal data. Teleport's gogo-generated code surfaces raw generated-decoder messages like "illegal tag" that reference the message name and wire types directly. rqlite decodes over a raw TCP mux, so a misrouted port or HTTP-aware proxy produces the same unmarshal failure as true corruption.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 124 more across the corpus — use search.

Honest provenance: generated on 2026-09-04 from AI-assisted analysis of the linked records. See how records are made.