weaviate/weaviate · error
invalid packed digests length %d: not a multiple of %d
Error message
invalid packed digests length %d: not a multiple of %d
What it means
RepairDigestsFromBinary decodes a packed payload of fixed-size records (CompareDigestsRecordLength = 25 bytes: 16-byte UUID + 8-byte big-endian timestamp + 1 flag byte). If the total length is not an exact multiple of the record size, the payload is malformed — it cannot be split into whole records — and decoding is rejected before any parsing.
Source
Thrown at usecases/replica/repair_digests_codec.go:52
out := make([]byte, 0, len(digests)*CompareDigestsRecordLength)
var buf [CompareDigestsRecordLength]byte
for _, d := range digests {
copy(buf[:16], d.ID[:])
binary.BigEndian.PutUint64(buf[16:24], uint64(d.UpdateTime))
buf[24] = 0
if d.Deleted {
buf[24] = CompareDigestsFlagDeleted
}
out = append(out, buf[:]...)
}
return out
}
// RepairDigestsFromBinary decodes a RepairDigestsToBinary payload, rejecting
// any length that is not a whole number of records.
func RepairDigestsFromBinary(data []byte) ([]types.RepairDigest, error) {
if len(data)%CompareDigestsRecordLength != 0 {
return nil, fmt.Errorf("invalid packed digests length %d: not a multiple of %d",
len(data), CompareDigestsRecordLength)
}
digests := make([]types.RepairDigest, len(data)/CompareDigestsRecordLength)
for i := range digests {
rec := data[i*CompareDigestsRecordLength : (i+1)*CompareDigestsRecordLength]
id, err := uuid.FromBytes(rec[:16])
if err != nil {
return nil, fmt.Errorf("parse uuid from binary record: %w", err)
}
digests[i] = types.RepairDigest{
ID: id,
UpdateTime: int64(binary.BigEndian.Uint64(rec[16:24])),
Deleted: rec[24]&CompareDigestsFlagDeleted != 0,
}
}
return digests, nil
}
View on GitHub (pinned to 75aa4b6d11)
Solutions
- Verify the sender negotiated the packed encoding (RepairDigestsEncodingPacked) and did not fall back to the proto encoding — mismatched encodings change the byte layout.
- Log the payload length and compare against (expected record count) * 25 to spot truncation or trailing bytes.
- Retransmit the digest payload; a single corrupted transfer is the usual cause.
- If a peer persistently produces bad lengths, check its Weaviate version for codec bugs and align versions.
Example fix
// before: assume packed blindly | digests, err := replica.RepairDigestsFromBinary(body) | // after: guard on negotiated encoding first | if encoding == replica.RepairDigestsEncodingPacked { digests, err = replica.RepairDigestsFromBinary(body) } else { digests = decodeRepeatedProto(body) } Defensive patterns
Strategy: validation
Validate before calling
const recordLen = 25; if len(payload)%recordLen != 0 { return fmt.Errorf("payload %d not multiple of %d — wrong encoding or truncated", len(payload), recordLen) } Try / catch
digests, err := replica.RepairDigestsFromBinary(body); if err != nil { /* fall back to the repeated-proto decoding path or request retransmission */ return nil, fmt.Errorf("packed digests rejected: %w", err) } Prevention
- Always send the encoding identifier alongside the payload so the decoder matches the writer's format.
- Check payload length before sending: len must equal recordCount * 25.
- Guard against proxies or middleware that re-frame or compress gRPC/REST bodies.
- Keep peer Weaviate versions aligned; legacy peers must stay on the repeated-proto path (encoding 0).
When it happens
Trigger: RepairDigestsFromBinary or decodePackedDigests receiving a payload whose byte length modulo 25 is nonzero: a peer sending the packed encoding with trailing bytes, truncated gRPC/REST transfer, an older peer sending the repeated-proto payload into the packed decoder, or compression/framing bytes left in the buffer.
Common situations: Version skew where one node claims RepairDigestsEncodingPacked but sends the legacy repeated-proto body; network truncation; a proxy or middleware altering the body; handcrafted test payloads.
Related errors
- couldn't connect to remote contextionary gRPC server: %w
- could not get vector from remote: %w
- could not get nearest words by vector: %w
- word '%s': %w
- could not check word presence: %w
AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04).
Data as JSON: /api/errors/334d8bb2f2537c79.
Report an issue: GitHub.