VictoriaMetrics/VictoriaMetrics · error

cannot read uint64: %w

Error message

cannot read uint64: %w

What it means

Returned by vmselectRequestCtx.readUint64 when io.ReadFull cannot read the full 8 bytes of a uint64 field from the vmselect connection and the error is not a clean EOF. The underlying io error is wrapped with %w. Like the uint32 variant, it signals a truncated or broken binary protocol stream (readTimeRange, processRegisterMetricNames callers).

Source

Thrown at lib/vmselectapi/server.go:339

func (ctx *vmselectRequestCtx) readUint32() (uint32, error) {
	ctx.sizeBuf = bytesutil.ResizeNoCopyMayOverallocate(ctx.sizeBuf, 4)
	if _, err := io.ReadFull(ctx.bc, ctx.sizeBuf); err != nil {
		if err == io.EOF {
			return 0, err
		}
		return 0, fmt.Errorf("cannot read uint32: %w", err)
	}
	n := encoding.UnmarshalUint32(ctx.sizeBuf)
	return n, nil
}

func (ctx *vmselectRequestCtx) readUint64() (uint64, error) {
	ctx.sizeBuf = bytesutil.ResizeNoCopyMayOverallocate(ctx.sizeBuf, 8)
	if _, err := io.ReadFull(ctx.bc, ctx.sizeBuf); err != nil {
		if err == io.EOF {
			return 0, err
		}
		return 0, fmt.Errorf("cannot read uint64: %w", err)
	}
	n := encoding.UnmarshalUint64(ctx.sizeBuf)
	return n, nil
}

func (ctx *vmselectRequestCtx) readInt64() (int64, error) {
	ctx.sizeBuf = bytesutil.ResizeNoCopyMayOverallocate(ctx.sizeBuf, 8)
	if _, err := io.ReadFull(ctx.bc, ctx.sizeBuf); err != nil {
		if err == io.EOF {
			return 0, err
		}
		return 0, fmt.Errorf("cannot read int64: %w", err)
	}
	n := encoding.UnmarshalInt64(ctx.sizeBuf)
	return n, nil
}

func (ctx *vmselectRequestCtx) readAccountIDProjectID() (uint32, uint32, error) {

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Confirm the client writes uint64 fields as exactly 8 bytes little-endian.
  2. Inspect the wrapped error: unexpected-EOF implies truncated write; reset implies dropped connection.
  3. Align VictoriaMetrics component versions (vmagent/vminsert vs vmselect).
  4. Check idle/read timeouts on load balancers between cluster components.
  5. Retry on a new connection.

Example fix

// before (4-byte timestamp)
binary.LittleEndian.PutUint32(buf, uint32(ts))
// after
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(ts))
conn.Write(b)
Defensive patterns

Strategy: try-catch

Validate before calling

// client side
var v uint64
binary.LittleEndian.PutUint64(buf, v) // exactly 8 bytes, never manual append

Type guard

func isTruncatedRead(err error) bool { return errors.Is(err, io.ErrUnexpectedEOF) }

Try / catch

v, err := readUint64(conn)
if err != nil {
    if errors.Is(err, io.EOF) { return io.EOF }
    return fmt.Errorf("failed reading uint64 field: %w", err)
}

Prevention

When it happens

Trigger: A caller sends fewer than 8 bytes for a time-range / timestamp field read by readTimeRange or processRegisterMetricNames; the connection is reset or times out while reading the 8-byte value.

Common situations: Custom clients writing timestamps as 4 bytes instead of 8; half-closed connections where the peer finished early; proxy buffering limits truncating the request; version-skewed cluster nodes.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/d5172d3fe2e78372. Report an issue: GitHub.