vitessio/vitess · error

use of closed connection

Error message

use of closed connection

What it means

fakevtsql.ErrConnClosed is returned by the fake vtsql connection's QueryContext when a query is attempted on a connection that has already been Closed. It intentionally duplicates vtsql.ErrConnClosed's message to avoid an import cycle in vtsql's tests. It is a test-double error, seen only in code exercising vtadmin code paths against the fake driver.

Source

Thrown at go/vt/vtadmin/vtsql/fakevtsql/conn.go:38

	"context"
	"database/sql/driver"
	"errors"
	"fmt"
	"strings"

	"github.com/stretchr/testify/assert"

	"vitess.io/vitess/go/vt/topo/topoproto"
	"vitess.io/vitess/go/vt/vtadmin/vtadminproto"

	vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
)

var (
	// ErrConnClosed is returend when attempting to query a closed connection.
	// It is the identical message to vtsql.ErrConnClosed, but redefined to
	// prevent an import cycle in package vtsql's tests.
	ErrConnClosed = errors.New("use of closed connection")
	// ErrUnrecognizedQuery is returned when QueryCnotext is given a query
	// string the mock is not set up to handle.
	ErrUnrecognizedQuery = errors.New("unrecognized query")
)

type conn struct {
	tablets   []*vtadminpb.Tablet
	shouldErr bool
}

var (
	_ driver.Conn           = (*conn)(nil)
	_ driver.QueryerContext = (*conn)(nil)
)

func (c *conn) Begin() (driver.Tx, error) {
	return nil, nil
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Inspect test/service code for a Close followed by a query on the same conn
  2. Reopen or create a fresh fakevtsql connection before the next query
  3. If intentional, compare against the sentinel: errors.Is/err == fakevtsql.ErrConnClosed to handle it

Example fix

// before
conn.Close()
rows, err := conn.QueryContext(ctx, "select 1")
// after
rows, err := conn.QueryContext(ctx, "select 1")
// ... use rows ...
conn.Close()
Defensive patterns

Strategy: try-catch

Validate before calling

if conn == nil || conn.Closed() {
    return fmt.Errorf("refusing to query closed fakevtsql conn")
}

Type guard

func isConnClosed(err error) bool { return errors.Is(err, fakevtsql.ErrConnClosed) }

Try / catch

rows, err := conn.QueryContext(ctx, q)
if errors.Is(err, fakevtsql.ErrConnClosed) {
    // reopen or fail the test with a clear message
}

Prevention

When it happens

Trigger: Calling QueryContext (or Execute) on a fakevtsql conn after Close was called on it, typically when code under test closes the connection then issues another query.

Common situations: vtadmin service code that reuses a connection after close; tests asserting connection cleanup; double-close scenarios in vtsql test suites.

Related errors


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