{"id":"6d486e533580f912","repo":"jackc/pgx","slug":"too-many-column-format-codes-6d486e","errorCode":null,"errorMessage":"too many column format codes","messagePattern":"too many column format codes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgproto3/copy_out_response.go","lineNumber":53,"sourceCode":"\n\tcolumnFormatCodes := make([]uint16, columnCount)\n\tfor i := range columnCount {\n\t\tcolumnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))\n\t}\n\n\t*dst = CopyOutResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}\n\n\treturn nil\n}\n\n// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.\nfunc (src *CopyOutResponse) Encode(dst []byte) ([]byte, error) {\n\tdst, sp := beginMessage(dst, 'H')\n\n\tdst = append(dst, src.OverallFormat)\n\n\tif len(src.ColumnFormatCodes) > math.MaxUint16 {\n\t\treturn nil, errors.New(\"too many column format codes\")\n\t}\n\tdst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))\n\tfor _, fc := range src.ColumnFormatCodes {\n\t\tdst = pgio.AppendUint16(dst, fc)\n\t}\n\n\treturn finishMessage(dst, sp)\n}\n\n// MarshalJSON implements encoding/json.Marshaler.\nfunc (src CopyOutResponse) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(struct {\n\t\tType              string\n\t\tColumnFormatCodes []uint16\n\t}{\n\t\tType:              \"CopyOutResponse\",\n\t\tColumnFormatCodes: src.ColumnFormatCodes,\n\t})","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgproto3/copy_out_response.go#L35-L71","documentation":"Returned by CopyOutResponse.Encode when ColumnFormatCodes has more than 65535 entries. The column count is a uint16 on the wire, so the library rejects oversized slices rather than truncating. CopyOutResponse is the 'H' message the server sends to begin a COPY TO STDOUT (server→client export) operation.","triggerScenarios":"Calling `(*CopyOutResponse).Encode(dst)` with `len(ColumnFormatCodes) > 65535`. Like the other Copy responses, this is server-originated; the error only fires in a proxy/server/test harness, not in a standard pgx client.","commonSituations":"A proxy or fuzzer constructs a CopyOutResponse for an artificial table with >64k columns, or a mis-scoped loop appends format codes beyond the column count.","solutions":["Cap ColumnFormatCodes at 65535; a one-element slice applies the format to all columns.","Inspect the construction code for an unbounded or per-row append loop.","When proxying, pass through the server's raw encoded bytes instead of re-encoding.","Confirm the column count value is not a corrupted upstream read."],"exampleFix":"// before\nresp := &pgproto3.CopyOutResponse{\n    OverallFormat:     0,\n    ColumnFormatCodes: hugeCodes, // > 65535\n}\n_, err := resp.Encode(nil)\n\n// after\nresp := &pgproto3.CopyOutResponse{\n    OverallFormat:     0,\n    ColumnFormatCodes: []uint16{0},\n}\n_, err := resp.Encode(nil)","handlingStrategy":"validation","validationCode":"func validateCopyOutResponseEncode(r *pgproto3.CopyOutResponse) error {\n\tif len(r.ColumnFormatCodes) > math.MaxUint16 {\n\t\treturn fmt.Errorf(\"too many column format codes: %d (max %d)\", len(r.ColumnFormatCodes), math.MaxUint16)\n\t}\n\treturn nil\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Use a one-element ColumnFormatCodes slice for uniform formats.","Cap column counts at 65535.","Forward server bytes verbatim in proxies."],"tags":["pgproto3","protocol","encoding","copy","wire-protocol","validation"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}