jackc/pgx · error

no reference to batch

Error message

no reference to batch

What it means

Returned by (*pipelineBatchResults).nextQueryAndArgs when br.b is nil — the pipeline BatchResults object has no pointer back to the originating Batch. pgx constructs pipelineBatchResults with b set inside SendBatch, so a nil batch indicates an internal invariant violation or a result object that was not produced through the normal SendBatch path. The reader cannot correlate the next server result with any queued query.

Source

Thrown at batch.go:443

	}

	br.closed = true

	err := br.pipeline.Close()
	if br.err == nil {
		br.err = err
	}

	return br.err
}

func (br *pipelineBatchResults) earlyError() error {
	return br.err
}

func (br *pipelineBatchResults) nextQueryAndArgs() (query string, args []any, err error) {
	if br.b == nil {
		return "", nil, errors.New("no reference to batch")
	}

	if br.qqIdx >= len(br.b.QueuedQueries) {
		return "", nil, errors.New("no more results in batch")
	}

	bi := br.b.QueuedQueries[br.qqIdx]
	br.qqIdx++
	return bi.SQL, bi.Arguments, nil
}

type emptyBatchResults struct {
	conn   *Conn
	closed bool
}

// Exec reads the results from the next query in the batch as if the query has been sent with Exec.
func (br *emptyBatchResults) Exec() (pgconn.CommandTag, error) {

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. Only obtain BatchResults from Conn.SendBatch (or the pool/tx equivalents); never construct pipelineBatchResults yourself.
  2. Report this as a pgx bug if reached through the public API — the batch pointer should always be populated.
  3. If writing a custom BatchResults implementation for testing, return emptyBatchResults or your own type rather than reusing pipelineBatchResults.
  4. Update to the latest pgx patch release in case the invariant was restored.

Example fix

// before (test double)
br := &pipelineBatchResults{ctx: ctx, conn: c, pipeline: p} // missing b
_, err := br.Exec()

// after
br := &pipelineBatchResults{ctx: ctx, conn: c, pipeline: p, b: batch}
Defensive patterns

Strategy: validation

Validate before calling

// Only ever obtain BatchResults from SendBatch:
if batch == nil || len(batch.QueuedQueries) == 0 {
    // send nothing / use emptyBatchResults semantics
    return nil
}
br := conn.SendBatch(ctx, batch)

Try / catch

if _, err := br.Exec(); err != nil {
    if strings.Contains(err.Error(), "no reference to batch") {
        return fmt.Errorf("internal: BatchResults has no batch; report upstream")
    }
    return err
}

Prevention

When it happens

Trigger: Calling Exec()/Query()/QueryRow() on a *pipelineBatchResults whose Batch pointer is nil. In normal API use SendBatch always sets it, so this surfaces from internal construction bugs, reflection/test doubles that build pipelineBatchResults without b, or a future code path that sends a pipeline query without a Batch.

Common situations: Test scaffolding or wrappers that synthesize BatchResults manually; an internal pgx bug after a refactor; calling methods on a pipelineBatchResults struct created directly rather than via SendBatch.

Related errors


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/3e7ab340ecea96ad.json. Report an issue: GitHub.