VictoriaMetrics/VictoriaMetrics · error
cannot read accountID: %w
Error message
cannot read accountID: %w
What it means
Wrapping error from vmselectRequestCtx.readAccountIDProjectID when its first readUint32 call (accountID) fails. It chains the underlying error from reading the 4-byte accountID field. This means the tenant identifier at the start of the request packet could not be read — the stream was truncated or the connection broke.
Source
Thrown at lib/vmselectapi/server.go:360
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) {
accountID, err := ctx.readUint32()
if err != nil {
return 0, 0, fmt.Errorf("cannot read accountID: %w", err)
}
projectID, err := ctx.readUint32()
if err != nil {
return 0, 0, fmt.Errorf("cannot read projectID: %w", err)
}
return accountID, projectID, nil
}
// maxSearchQuerySize is the maximum size of SearchQuery packet in bytes.
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5154#issuecomment-1757216612
const maxSearchQuerySize = 5 * 1024 * 1024
func (ctx *vmselectRequestCtx) readSearchQuery() error {
if err := ctx.readDataBufBytes(maxSearchQuerySize); err != nil {
return fmt.Errorf("cannot read searchQuery: %w", err)
}
tail, err := ctx.sq.Unmarshal(ctx.dataBuf)
if err != nil {View on GitHub (pinned to 5079fb58f1)
Solutions
- Ensure the client writes accountID (4 bytes LE) as the first field of the request packet.
- Verify network path stability between the caller and vmselect.
- Check the wrapped error for the concrete cause.
- Use /proc/<pid>/limits or connection logs to rule out abrupt disconnects; retry on new connection.
- Align component versions.
Example fix
// before (tenant prefix omitted) writeSearchQuery(conn, sq) // after writeUint32(conn, accountID) writeUint32(conn, projectID) writeSearchQuery(conn, sq)
Defensive patterns
Strategy: validation
Validate before calling
// validate tenant prefix exists before sending packet
if !packetHasTenantPrefix(buf) {
return errors.New("internal select requests must start with accountID+projectID")
} Try / catch
accountID, projectID, err := readAccountIDProjectID(conn)
if err != nil {
return fmt.Errorf("tenant header read failed: %w", err)
} Prevention
- Always prefix internal protocol requests with accountID (4B LE) then projectID (4B LE), even in single-tenant mode
- Verify partial writes: check n == len(buf) after conn.Write
- Test against a real vmselect before deploying custom clients
- Log the wrapped cause for every tenant-header failure
When it happens
Trigger: processTagValueSuffixes or processSeriesCount receives a packet shorter than the initial 4-byte accountID, or the connection errors while reading it.
Common situations: Clients omitting the accountID/projectID prefix required by the internal protocol (default single-tenant setups forgetting to write tenant IDs); truncated writes; dropped connections.
Related errors
- cannot read projectID: %w
- cannot read uint32: %w
- cannot read uint64: %w
- cannot read int64: %w
- cannot read searchQuery: %w
AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03).
Data as JSON: /api/errors/264a6280ba7bc971.
Report an issue: GitHub.