{"id":"ba3d8856d72b6230","repo":"jackc/pgx","slug":"no-more-results-in-batch","errorCode":null,"errorMessage":"no more results in batch","messagePattern":"no more results in batch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"batch.go","lineNumber":143,"sourceCode":"\tclosed    bool\n\tendTraced bool\n}\n\n// Exec reads the results from the next query in the batch as if the query has been sent with Exec.\nfunc (br *batchResults) Exec() (pgconn.CommandTag, error) {\n\tif br.err != nil {\n\t\treturn pgconn.CommandTag{}, br.err\n\t}\n\tif br.closed {\n\t\treturn pgconn.CommandTag{}, fmt.Errorf(\"batch already closed\")\n\t}\n\n\tquery, arguments, _ := br.nextQueryAndArgs()\n\n\tif !br.mrr.NextResult() {\n\t\terr := br.mrr.Close()\n\t\tif err == nil {\n\t\t\terr = errors.New(\"no more results in batch\")\n\t\t}\n\t\tif br.conn.batchTracer != nil {\n\t\t\tbr.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{\n\t\t\t\tSQL:  query,\n\t\t\t\tArgs: arguments,\n\t\t\t\tErr:  err,\n\t\t\t})\n\t\t}\n\t\treturn pgconn.CommandTag{}, err\n\t}\n\n\tcommandTag, err := br.mrr.ResultReader().Close()\n\tif err != nil {\n\t\tbr.err = err\n\t\tbr.mrr.Close()\n\t}\n\n\tif br.conn.batchTracer != nil {","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/batch.go#L125-L161","documentation":"Returned by (*batchResults).Exec when the underlying MultiResultReader reports no further result sets. pgx asked PostgreSQL for the next result of a pipelined batch and got ReadyForQuery instead, so the read index advanced past the last executed query. The message means the client consumed more result slots than it queued (or a server-side error aborted the remaining statements, suppressing their result sets).","triggerScenarios":"Calling Exec() on the BatchResults returned by Conn.SendBatch more times than Batch.Queue was called. Also reachable when an earlier query in the batch errors on the server: PostgreSQL aborts the implicit transaction and emits no result sets for the remaining queued queries, so a subsequent Exec() finds nothing.","commonSituations":"Mismatch between the number of Queue() calls and the number of Exec()/Query()/Close()-driven reads; a failed earlier statement that short-circuits the batch; upgrading a loop that previously added an extra read for a trailing row count.","solutions":["Drive results through callbacks via QueuedQuery.Exec/Query/QueryRow and rely on BatchResults.Close, instead of manually calling Exec() N times.","Make sure the number of result reads (Exec/Query/QueryRow) equals Batch.Len(); track the count in the same place you call Queue.","Inspect any error returned before this one (br.err / the previous Exec return) — a server error earlier in the batch will make every subsequent read surface 'no more results in batch' as a secondary symptom.","If you conditionally skip Queue calls, conditionally skip the matching reads in the same branch."],"exampleFix":"// before\nbr := conn.SendBatch(ctx, batch)\nfor i := 0; i < 5; i++ { // hardcoded count drifted from batch.Len()\n    _, err := br.Exec()\n    if err != nil { return err } // hits \"no more results in batch\"\n}\nbr.Close()\n\n// after\nbr := conn.SendBatch(ctx, batch)\nfor i := 0; i < batch.Len(); i++ {\n    _, err := br.Exec()\n    if err != nil { return err }\n}\nreturn br.Close()","handlingStrategy":"validation","validationCode":"if batch.Len() == 0 { return nil }\nreadCount := 0\nbr := conn.SendBatch(ctx, batch)\nfor readCount < batch.Len() {\n    if _, err := br.Exec(); err != nil { _ = br.Close(); return err }\n    readCount++\n}\nreturn br.Close()","typeGuard":null,"tryCatchPattern":"br := conn.SendBatch(ctx, batch)\ndefer func() { _ = br.Close() }()\nfor i := 0; i < batch.Len(); i++ {\n    if _, err := br.Exec(); err != nil {\n        if err.Error() == \"no more results in batch\" {\n            // earlier query failed and aborted the batch; check prior error\n        }\n        return err\n    }\n}","preventionTips":["Prefer QueuedQuery callbacks over manual Exec/Query loops so pgx tracks the read index.","Always gate SendBatch on batch.Len()>0.","Stop reading immediately when any result returns an error."],"tags":["batch","pipelining","query-execution"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}