jackc/pgx · error
too many column format codes
Error message
too many column format codes
What it means
Returned by CopyBothResponse.Encode when ColumnFormatCodes has more than 65535 entries. The wire format encodes the column count as a uint16, so anything beyond MaxUint16 cannot be represented. This guard prevents emitting a silently-truncated count that the receiver would misinterpret. CopyBothResponse is the 'W' message used in logical/physical streaming replication.
Source
Thrown at pgproto3/copy_both_response.go:52
return &invalidMessageFormatErr{messageType: "CopyBothResponse"}
}
columnFormatCodes := make([]uint16, columnCount)
for i := range columnCount {
columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
}
*dst = CopyBothResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
return nil
}
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyBothResponse) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'W')
dst = append(dst, src.OverallFormat)
if len(src.ColumnFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many column format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
for _, fc := range src.ColumnFormatCodes {
dst = pgio.AppendUint16(dst, fc)
}
return finishMessage(dst, sp)
}
// MarshalJSON implements encoding/json.Marshaler.
func (src CopyBothResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
ColumnFormatCodes []uint16
}{
Type: "CopyBothResponse",
ColumnFormatCodes: src.ColumnFormatCodes,
})View on GitHub (pinned to ec1a0befd2)
Solutions
- Cap ColumnFormatCodes at 65535 entries; if you have more columns you cannot represent them in one CopyBothResponse.
- Reuse a single format code for all columns when they share a format — the protocol allows one entry to apply to all.
- Audit the code that builds ColumnFormatCodes for an unbounded loop or accidental append inside a row loop.
- If proxying a server, forward the server's encoded bytes verbatim instead of re-encoding.
Example fix
// before
resp := &pgproto3.CopyBothResponse{
OverallFormat: 0,
ColumnFormatCodes: perColumnCodes, // len > 65535
}
_, err := resp.Encode(nil)
// after
resp := &pgproto3.CopyBothResponse{
OverallFormat: 0,
ColumnFormatCodes: []uint16{0}, // single code applies to all columns
}
_, err := resp.Encode(nil) Defensive patterns
Strategy: validation
Validate before calling
func validateCopyBothResponseEncode(r *pgproto3.CopyBothResponse) error {
if len(r.ColumnFormatCodes) > math.MaxUint16 {
return fmt.Errorf("too many column format codes: %d (max %d)", len(r.ColumnFormatCodes), math.MaxUint16)
}
return nil
} Type guard
null
Try / catch
null
Prevention
- Use a single-element ColumnFormatCodes slice when all columns share a format.
- Cap column counts at 65535 at the construction site.
- Forward server bytes verbatim in proxies rather than re-encoding.
When it happens
Trigger: Calling `(*CopyBothResponse).Encode(dst)` with `len(ColumnFormatCodes) > 65535`. Realistic only in a test harness, a replication proxy synthesising a response, or a bug that builds a per-column slice for a table with >64k columns.
Common situations: Almost never hit by application code — CopyBothResponse is a backend→frontend message normally produced by the server, not by the client. Surfaces when writing a PostgreSQL-compatible proxy/server or a fuzzer that constructs oversized messages. A misconfigured replication proxy that loops while appending format codes could trigger it.
Related errors
- too many column format codes
- too many column format codes
- secret key too long
- too many values
- too many arg format codes
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/1a27e69b22b7ab24.json.
Report an issue: GitHub.