jackc/pgx · error
too many arg format codes
Error message
too many arg format codes
What it means
Returned by FunctionCall.Encode when ArgFormatCodes has more than 65535 entries. The count is encoded as a uint16, so MaxUint16 is the ceiling; the guard prevents a truncated count. FunctionCall is the legacy 'F' message (the v3 function-call protocol), where each entry is 0 (text) or 1 (binary).
Source
Thrown at pgproto3/function_call.go:103
// The format code for the function result. Must presently be zero (text) or one (binary).
if len(src[rp:]) < 2 {
return &invalidMessageFormatErr{messageType: "FunctionCall"}
}
resultFormatCode := binary.BigEndian.Uint16(src[rp:])
if resultFormatCode != 0 && resultFormatCode != 1 {
return &invalidMessageFormatErr{messageType: "FunctionCall"}
}
dst.ResultFormatCode = resultFormatCode
return nil
}
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'F')
dst = pgio.AppendUint32(dst, src.Function)
if len(src.ArgFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many arg format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
for _, argFormatCode := range src.ArgFormatCodes {
dst = pgio.AppendUint16(dst, argFormatCode)
}
if len(src.Arguments) > math.MaxUint16 {
return nil, errors.New("too many arguments")
}
dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
for _, argument := range src.Arguments {
if argument == nil {
dst = pgio.AppendInt32(dst, -1)
} else {
dst = pgio.AppendInt32(dst, int32(len(argument)))
dst = append(dst, argument...)
}
}View on GitHub (pinned to ec1a0befd2)
Solutions
- Cap ArgFormatCodes at 65535; a single-entry slice applies the format to all arguments (the protocol explicitly allows this).
- Audit the construction loop for accidental duplication or per-row instead of per-arg appends.
- Prefer a single format code shared by all arguments when formats are uniform.
- Pre-validate length before encoding and return a clear error.
Example fix
// before
fc := &pgproto3.FunctionCall{
Function: oid,
ArgFormatCodes: perArgCodes, // > 65535
}
_, err := fc.Encode(nil)
// after
fc := &pgproto3.FunctionCall{
Function: oid,
ArgFormatCodes: []uint16{0}, // one code applies to all args
}
_, err := fc.Encode(nil) Defensive patterns
Strategy: validation
Validate before calling
func validateFunctionCallFormatCodes(fc *pgproto3.FunctionCall) error {
if len(fc.ArgFormatCodes) > math.MaxUint16 {
return fmt.Errorf("too many arg format codes: %d (max %d)", len(fc.ArgFormatCodes), math.MaxUint16)
}
return nil
} Type guard
null
Try / catch
null
Prevention
- Use a single ArgFormatCodes entry when all args share a format (protocol allows it).
- Cap format-code slices at 65535 at construction.
- Audit loops for per-row instead of per-arg appends.
When it happens
Trigger: Calling `(*FunctionCall).Encode(dst)` with `len(ArgFormatCodes) > 65535`. Realistic only in synthetic code, a fuzzer, or a caller that builds one format code per argument for a function with >64k args.
Common situations: The function-call protocol is rarely used by modern applications (prepared statements are preferred). A caller migrating an old libpq-style codebase that calls a function with a huge argument list, or a test harness stress-testing the encoder, could hit this. More often it signals a loop that over-appends.
Related errors
- too many arguments
- secret key too long
- too many column format codes
- too many column format codes
- too many column format codes
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/992bf58c5012313f.json.
Report an issue: GitHub.