vitessio/vitess · error

unexpected number of rows returned (%d) from connection_id()

Error message

unexpected number of rows returned (%d) from connection_id() query

What it means

After copying a table, execPostCopyActions runs 'select connection_id()' on its own DB client to record the connection so it can be KILLed if the workflow is interrupted. This error is thrown when the query returns a result set with anything other than exactly one row (or a nil result), which the connection_id() function should never do. It is a defensive check against an unexpected server/client behavior.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/vreplicator.go:979

	if err != nil {
		return err
	}
	// qr should never be nil, but check anyway to be extra safe.
	if qr == nil || len(qr.Rows) == 0 {
		return nil
	}

	vr.insertLog(LogCopyStart, fmt.Sprintf("Executing %d post copy action(s) for %s table", len(qr.Rows), tableName))

	// Save our connection ID so we can use it to easily KILL any
	// running SQL action we may perform later if needed.
	idqr, err := dbClient.ExecuteFetch("select connection_id()", 1)
	if err != nil {
		return err
	}
	// qr should never be nil, but check anyway to be extra safe.
	if idqr == nil || len(idqr.Rows) != 1 {
		return fmt.Errorf("unexpected number of rows returned (%d) from connection_id() query", len(idqr.Rows))
	}
	connID, err := idqr.Rows[0][0].ToInt64()
	if err != nil || connID == 0 {
		return fmt.Errorf("unexpected result (%d) from connection_id() query, error: %v", connID, err)
	}

	deleteAction := func(dbc *vdbClient, id int64, vid int32, tn string) error {
		delq, err := sqlparser.ParseAndBind(sqlDeletePostCopyAction, sqltypes.Int32BindVariable(vid),
			sqltypes.StringBindVariable(tn), sqltypes.Int64BindVariable(id))
		if err != nil {
			return err
		}
		if _, err := dbc.ExecuteFetch(delq, 1); err != nil {
			return fmt.Errorf("failed to delete post copy action for the %q table with id %d: %v",
				tableName, id, err)
		}
		return nil
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Retry the workflow — the copy phase restarts and re-establishes a fresh connection
  2. Check MySQL server health and error logs for connection or protocol errors around the time of the failure
  3. Verify the tablet's MySQL version is supported by this Vitess release
  4. If reproducible, file a Vitess issue with tablet and MySQL logs
Defensive patterns

Strategy: retry

Validate before calling

idqr, err := dbClient.ExecuteFetch("select connection_id()", 1)
if err == nil && idqr != nil && len(idqr.Rows) == 1 {
    if v, verr := idqr.Rows[0][0].ToInt64(); verr == nil && v > 0 { /* connection healthy */ }
}

Type guard

func validSingleRowResult(qr *sqltypes.Result) bool {
    return qr != nil && len(qr.Rows) == 1 && len(qr.Rows[0]) > 0
}

Try / catch

if err != nil || idqr == nil || len(idqr.Rows) != 1 {
    // treat as transient server anomaly: reconnect and retry the phase
    return retryWorkflowPhase()
}

Prevention

When it happens

Trigger: execPostCopyActions (invoked via copyTable / runPostCopyActionsAndDeleteCopyActions) executes 'select connection_id()' and the returned *sqltypes.Result is nil or len(idqr.Rows) != 1 — e.g. the underlying MySQL connection returned a corrupted or empty result.

Common situations: MySQL server misbehaving or an incompatibility in the MySQL/vitess client stack returning empty results; transient connection state corruption; this should essentially never occur in healthy deployments.

Related errors


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