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
- Inspect test/service code for a Close followed by a query on the same conn
- Reopen or create a fresh fakevtsql connection before the next query
- 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
- Close connections only after all queries complete
- Avoid double-close patterns
- Assert in tests that no query follows Close
- Use defer close only at the end of the usage scope
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
- unrecognized query
- bad sql row
- err rows closed
- not allowed: deny-all security-policy enforced
- not allowed: read-only security-policy enforced
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/b0c5633efb952bac.
Report an issue: GitHub.