{"record":{"id":"e088ae226d4908da","repo":"vitessio/vitess","slug":"err-rows-closed","errorCode":null,"errorMessage":"err rows closed","messagePattern":"err rows closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtadmin/vtsql/fakevtsql/rows.go","lineNumber":32,"sourceCode":"limitations under the License.\n*/\n\npackage fakevtsql\n\nimport (\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n)\n\nvar (\n\t// ErrBadRow is returned from Next() when a row has an incorrect number of\n\t// fields.\n\tErrBadRow = errors.New(\"bad sql row\")\n\t// ErrRowsClosed is returned when attempting to operate on an already-closed\n\t// Rows.\n\tErrRowsClosed = errors.New(\"err rows closed\")\n)\n\ntype rows struct {\n\tcols []string\n\tvals [][]any\n\tpos  int\n\n\tclosed bool\n}\n\nvar _ driver.Rows = (*rows)(nil)\n\nfunc (r *rows) Close() error {\n\tr.closed = true\n\treturn nil\n}\n\nfunc (r *rows) Columns() []string {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/vtsql/fakevtsql/rows.go#L14-L50","documentation":"fakevtsql.ErrRowsClosed is returned by rows.Next (and other row operations) on a fake Rows that has already been Closed. It guards against iterating a result set after it was consumed or closed. Seen only in tests using the fake vtsql driver.","triggerScenarios":"Calling Next after Close on the fake rows; iterating a rows object twice; code under test draining rows then reading again.","commonSituations":"Test code that re-reads a result set; service code that scans rows after defer rows.Close() has run due to ordering issues.","solutions":["Scan all rows before calling rows.Close()","Do not reuse a closed Rows; re-execute the query to get a new result set","Check ordering of deferred Close vs later row reads"],"exampleFix":"// before\nrows.Close()\nrows.Next()\n// after\nfor rows.Next() { /* scan */ }\nrows.Close()","handlingStrategy":"try-catch","validationCode":"if rows.Closed() {\n    return fmt.Errorf(\"rows already closed\")\n}","typeGuard":"func isRowsClosed(err error) bool { return errors.Is(err, fakevtsql.ErrRowsClosed) }","tryCatchPattern":"if err := rows.Next(); errors.Is(err, fakevtsql.ErrRowsClosed) {\n    // stop iteration; do not reuse the rows object\n}","preventionTips":["Drain rows fully before Close","Never iterate a Rows twice","Check defer/Close ordering in code under test"],"tags":["vtadmin","test-double","database"],"backgroundTag":"rows-already-closed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}