geektutu/7days-golang · error
decoding response body: %v
Error message
decoding response body: %v
What it means
The day7 peer protocol encodes responses as protobuf; httpGetter.Get unmarshals the 200-response body into the out proto.Message with proto.Unmarshal. If the bytes are not a valid encoding of the expected message type, the failure is wrapped as "decoding response body: %v". This usually means the peer did not actually send a protobuf payload (wrong endpoint, wrong version, or a non-gee-cache server answering 200 with HTML/JSON).
Source
Thrown at gee-cache/day7-proto-buf/geecache/http.go:136
url.QueryEscape(in.GetKey()),
)
res, err := http.Get(u)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("server returned: %v", res.Status)
}
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("reading response body: %v", err)
}
if err = proto.Unmarshal(bytes, out); err != nil {
return fmt.Errorf("decoding response body: %v", err)
}
return nil
}
var _ PeerGetter = (*httpGetter)(nil)
View on GitHub (pinned to cf36443821)
Solutions
- Confirm both sides of the peer connection use the same protobuf message schema (consistent-cache/v1) and day7 code
- Verify the peer URL/basePath resolves to the gee-cache handler, not another endpoint returning 200
- Upgrade/downgrade nodes so the entire ring speaks the same protocol
- Log a preview of the raw bytes on this error to identify what the peer actually sent
Example fix
// before
// client expects protobuf but peer serves plain bytes (day5 node in ring)
var out pb.Response
proto.Unmarshal(bytes, out) // decoding response body: unexpected wire type
// after
// keep ring membership homogeneous:
peers.Add("http://node1:8001", "http://node2:8001") // all day7, same .proto schema Defensive patterns
Strategy: type-guard
Validate before calling
// cheap structural check before unmarshalling
if len(bytes) == 0 || bytes[0] > 20 { // protobuf fields start with small tags
return fmt.Errorf("peer response is not protobuf (%q)", preview(bytes))
} Type guard
func looksLikeProto(b []byte) bool {
return len(b) > 0 && b[0] < 20 // plausible protobuf field header
} Try / catch
err := g.Get(ctx, key, &out)
if err != nil {
if strings.Contains(err.Error(), "decoding response body") {
log.Printf("peer sent non-protobuf payload; check versions/basePath: %v", err)
return g.getLocally(key) // degrade gracefully
}
return err
} Prevention
- Keep all nodes on the same .proto schema and codegen version
- Never point the peer pool at a non-gee-cache endpoint (200 HTML pages decode-fail)
- Pin versions during rolling upgrades; probe peers for protocol capability
- Log a hex/preview of the body on decode errors to diagnose instantly
When it happens
Trigger: Hitting a day5/day6 (plain text) peer from a day7 client; basePath pointing at the wrong service that returns 200 with non-protobuf data; corrupted/truncated body that still passed ReadAll; a proxy error page served with 200.
Common situations: Rolling upgrades with mixed versions in the hash ring; misconfigured basePath such as "/" hitting the app's HTML index; manually constructed test requests against the wrong handler.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- server returned: %v
- server returned: %v
- reading response body: %v
- server returned: %v
- reading response body: %v
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/f8a6a8a8391fbbe4.
Report an issue: GitHub.