jackc/pgx · error

too many parameter format codes

Error message

too many parameter format codes

What it means

Returned by Bind.Encode in pgproto3/bind.go:122 when len(src.ParameterFormatCodes) exceeds 65535 (math.MaxUint16). The wire protocol encodes the parameter-format-code count as a uint16, so more than 65535 codes cannot be serialized. This is a caller-side guard fired while building the Bind message to send to the server, before any network I/O.

Source

Thrown at pgproto3/bind.go:122

	for i := range resultFormatCodeCount {
		dst.ResultFormatCodes[i] = int16(binary.BigEndian.Uint16(src[rp:]))
		rp += 2
	}

	return nil
}

// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Bind) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'B')

	dst = append(dst, src.DestinationPortal...)
	dst = append(dst, 0)
	dst = append(dst, src.PreparedStatement...)
	dst = append(dst, 0)

	if len(src.ParameterFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many parameter format codes")
	}
	dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes)))
	for _, fc := range src.ParameterFormatCodes {
		dst = pgio.AppendInt16(dst, fc)
	}

	if len(src.Parameters) > math.MaxUint16 {
		return nil, errors.New("too many parameters")
	}
	dst = pgio.AppendUint16(dst, uint16(len(src.Parameters)))
	for _, p := range src.Parameters {
		if p == nil {
			dst = pgio.AppendInt32(dst, -1)
			continue
		}

		dst = pgio.AppendInt32(dst, int32(len(p)))
		dst = append(dst, p...)

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. Cap ParameterFormatCodes at 65535; for uniform formats use a single code (the protocol applies one code to all params when count is 1).
  2. Batch the operation: split the query into chunks of <=65535 parameters.
  3. For bulk inserts, use COPY (pgx CopyFrom) instead of parameterized inserts.

Example fix

// before: one format code per parameter, blows past 65535
formats := make([]int16, 100000) // -> "too many parameter format codes"

// after: a single code applies to all parameters (protocol rule)
formats := []int16{0} // text format for every parameter
Defensive patterns

Strategy: validation

Validate before calling

const maxFormatCodes = 65535 // math.MaxUint16
if len(parameterFormatCodes) > maxFormatCodes {
    // Use a single code: the protocol applies one code to ALL parameters.
    parameterFormatCodes = []int16{parameterFormatCodes[0]}
}

Type guard

func bindFormatCodesOK(codes []int16) bool { return len(codes) <= 65535 }

Try / catch

if _, err := bindMsg.Encode(dst); err != nil {
    if strings.Contains(err.Error(), "too many parameter format codes") {
        // collapse to a single uniform code, or split the batch
        bindMsg.ParameterFormatCodes = []int16{bindMsg.ParameterFormatCodes[0]}
    }
}

Prevention

When it happens

Trigger: Constructing a Bind (or an extended-query ExecParams/ExecPrepared/Batch) with more than 65535 parameter format codes. In practice this means an explicit ParameterFormatCodes slice exceeding the limit, almost always an application bug since pgx normally generates at most one code per parameter.

Common situations: A query with an enormous IN-list or bulk insert built with >65535 placeholders; programmatically generating format codes in a loop without a cap; copying a result-set column count into format codes by mistake.

Related errors


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