vitessio/vitess · error

got wrong statement id from client %v, statement ID(%v) is n

Error message

got wrong statement id from client %v, statement ID(%v) is not found from record

What it means

A MySQL client sent a COM_STMT_SEND_LONG_DATA packet referencing a statement id that the server has no prepared-statement record for, so conn.go rejects it with this error and returns an error packet. It indicates the client's statement id does not match anything registered during COM_STMT_PREPARE — a client/server prepared-statement bookkeeping desync.

Source

Thrown at go/mysql/conn.go:1308

	if err := c.writeOKPacket(&PacketOK{statusFlags: c.StatusFlags}); err != nil {
		log.Error(fmt.Sprintf("Error writing ComStmtReset OK packet to client %v: %v", c.ConnectionID, err))
		return false
	}
	return true
}

func (c *Conn) handleComStmtSendLongData(data []byte) bool {
	stmtID, paramID, chunk, ok := c.parseComStmtSendLongData(data)
	c.recycleReadPacket()
	if !ok {
		err := fmt.Errorf("error parsing statement send long data from client %v, returning error: %v", c.ConnectionID, data)
		return c.writeErrorPacketFromErrorAndLog(err)
	}

	prepare, ok := c.PrepareData[stmtID]
	if !ok {
		err := fmt.Errorf("got wrong statement id from client %v, statement ID(%v) is not found from record", c.ConnectionID, stmtID)
		return c.writeErrorPacketFromErrorAndLog(err)
	}

	if prepare.BindVars == nil ||
		prepare.ParamsCount == uint16(0) ||
		paramID >= prepare.ParamsCount {
		err := fmt.Errorf("invalid parameter Number from client %v, statement: %v", c.ConnectionID, prepare.PrepareStmt)
		return c.writeErrorPacketFromErrorAndLog(err)
	}

	// COM_STMT_SEND_LONG_DATA is preparatory state for a later COM_STMT_EXECUTE,
	// not a separately logged query. Hold its ingress bytes so COM_STMT_EXECUTE
	// accounts for the full client payload used to run the statement.
	if c.pendingLongDataIngressBytes == nil {
		c.pendingLongDataIngressBytes = make(map[uint32]uint64)
	}
	c.pendingLongDataIngressBytes[stmtID] += c.currentCommandIngressBytes

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check the client driver/library version for known prepared-statement bugs and upgrade it
  2. Ensure the application prepares the statement on this same connection before sending long data and does not close it prematurely
  3. Disable client-side prepared-statement caching / reset connections cleanly (e.g. useCHARSET/reset settings) to avoid stale ids
  4. Inspect proxy/middleware in the path that may drop COM_STMT_PREPARE state

Example fix

// before: driver reuses stmt id after connection reset
stmt.SendLongData(id, param, data)
// after: re-prepare on new connection before sending
stmt := conn.Prepare(query)
stmt.SendLongData(id, param, data)
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side: only send long data for ids returned by the last PREPARE on this connection
if stmtID < 1 || stmtID > lastPrepareID(conn) { skipSend() }

Type guard

func statementKnown(conn *mysql.Conn, stmtID uint32) bool {
	_, ok := conn.PrepareData[stmtID]
	return ok
}

Try / catch

if err := c.handleStatementSendLongData(stmtID, ...); err != nil {
	// returns ERR packet to client; log connection id + stmtID for driver debugging
	return c.writeErrorPacketFromErrorAndLog(err)
}

Prevention

When it happens

Trigger: Client sends COM_STMT_SEND_LONG_DATA with stmtID not present in c.PrepareData — after the statement was closed (COM_STMT_CLOSE), never prepared on this connection, or a stale/reused id from a previous connection state.

Common situations: Client driver bugs or connection reuse after reset where prepared-statement ids are recycled; proxies/multiplexers replaying packets on a new connection; applications using mysql_stmt_send_long_data on statements closed earlier due to an error.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/7eaacb300fe458e2. Report an issue: GitHub.