{"record":{"id":"b0c5633efb952bac","repo":"vitessio/vitess","slug":"use-of-closed-connection","errorCode":null,"errorMessage":"use of closed connection","messagePattern":"use of closed connection","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtadmin/vtsql/fakevtsql/conn.go","lineNumber":38,"sourceCode":"\t\"context\"\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"vitess.io/vitess/go/vt/topo/topoproto\"\n\t\"vitess.io/vitess/go/vt/vtadmin/vtadminproto\"\n\n\tvtadminpb \"vitess.io/vitess/go/vt/proto/vtadmin\"\n)\n\nvar (\n\t// ErrConnClosed is returend when attempting to query a closed connection.\n\t// It is the identical message to vtsql.ErrConnClosed, but redefined to\n\t// prevent an import cycle in package vtsql's tests.\n\tErrConnClosed = errors.New(\"use of closed connection\")\n\t// ErrUnrecognizedQuery is returned when QueryCnotext is given a query\n\t// string the mock is not set up to handle.\n\tErrUnrecognizedQuery = errors.New(\"unrecognized query\")\n)\n\ntype conn struct {\n\ttablets   []*vtadminpb.Tablet\n\tshouldErr bool\n}\n\nvar (\n\t_ driver.Conn           = (*conn)(nil)\n\t_ driver.QueryerContext = (*conn)(nil)\n)\n\nfunc (c *conn) Begin() (driver.Tx, error) {\n\treturn nil, nil\n}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/vtsql/fakevtsql/conn.go#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"vtadmin service code that reuses a connection after close; tests asserting connection cleanup; double-close scenarios in vtsql test suites.","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"],"exampleFix":"// before\nconn.Close()\nrows, err := conn.QueryContext(ctx, \"select 1\")\n// after\nrows, err := conn.QueryContext(ctx, \"select 1\")\n// ... use rows ...\nconn.Close()","handlingStrategy":"try-catch","validationCode":"if conn == nil || conn.Closed() {\n    return fmt.Errorf(\"refusing to query closed fakevtsql conn\")\n}","typeGuard":"func isConnClosed(err error) bool { return errors.Is(err, fakevtsql.ErrConnClosed) }","tryCatchPattern":"rows, err := conn.QueryContext(ctx, q)\nif errors.Is(err, fakevtsql.ErrConnClosed) {\n    // reopen or fail the test with a clear message\n}","preventionTips":["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"],"tags":["vtadmin","test-double","database"],"backgroundTag":"use-of-closed-connection","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}