{"id":"9e9641b539b14919","repo":"jackc/pgx","slug":"cancel-request-too-long","errorCode":null,"errorMessage":"cancel request too long","messagePattern":"cancel request too long","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgproto3/cancel_request.go","lineNumber":27,"sourceCode":"\t\"github.com/jackc/pgx/v5/internal/pgio\"\n)\n\nconst cancelRequestCode = 80877102\n\ntype CancelRequest struct {\n\tProcessID uint32\n\tSecretKey []byte\n}\n\n// Frontend identifies this message as sendable by a PostgreSQL frontend.\nfunc (*CancelRequest) Frontend() {}\n\nfunc (dst *CancelRequest) Decode(src []byte) error {\n\tif len(src) < 12 {\n\t\treturn errors.New(\"cancel request too short\")\n\t}\n\tif len(src) > 264 {\n\t\treturn errors.New(\"cancel request too long\")\n\t}\n\n\trequestCode := binary.BigEndian.Uint32(src)\n\tif requestCode != cancelRequestCode {\n\t\treturn errors.New(\"bad cancel request code\")\n\t}\n\n\tdst.ProcessID = binary.BigEndian.Uint32(src[4:])\n\tdst.SecretKey = make([]byte, len(src)-8)\n\tcopy(dst.SecretKey, src[8:])\n\n\treturn nil\n}\n\n// Encode encodes src into dst. dst will include the 4 byte message length.\nfunc (src *CancelRequest) Encode(dst []byte) ([]byte, error) {\n\tif len(src.SecretKey) > 256 {\n\t\treturn nil, errors.New(\"secret key too long\")","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgproto3/cancel_request.go#L9-L45","documentation":"Returned by CancelRequest.Decode when the input exceeds 264 bytes. The cancel request body is capped at 8 header bytes plus a 256-byte secret key, matching the maximum the PostgreSQL server will accept. Anything larger indicates either a corrupt length prefix or a non-conformant sender, so the library rejects it to avoid unbounded allocation.","triggerScenarios":"`(*CancelRequest).Decode(src)` is called with `len(src) > 264`. Occurs on the receiving side of a cancel request (server, proxy, test harness) when the framed body is oversized.","commonSituations":"A corrupted length field upstream causes a huge buffer to be handed to Decode. Also seen when a bug in a proxy forwards the wrong message type into the cancel-request decoder, or when a fuzzed input produces a massively oversized payload.","solutions":["Confirm the framing layer (Frontend.Receive or your manual length-prefix parser) stripped the correct 4-byte length and handed only the declared body to Decode.","Log the actual `len(src)` — if it is enormous, the real bug is a bad length prefix or a misrouted message upstream, not the cancel decoder.","If you are building a server/proxy, enforce the 264-byte cap at the framing boundary and close connections that announce larger cancel bodies.","Check the sender is not appending trailing bytes (e.g. a stray NUL or a second message concatenated)."],"exampleFix":"// before\nerr := cr.Decode(body) // body is 400 bytes because the length prefix was misread\n\n// after\nif len(body) > 264 {\n    return fmt.Errorf(\"oversized cancel body: %d bytes (max 264)\", len(body))\n}\nerr := cr.Decode(body)","handlingStrategy":"validation","validationCode":"const maxCancelRequestBodyLen = 264\n\nfunc validateCancelRequestMaxLen(src []byte) error {\n\tif len(src) > maxCancelRequestBodyLen {\n\t\treturn fmt.Errorf(\"cancel request body too long: %d bytes (max %d)\", len(src), maxCancelRequestBodyLen)\n\t}\n\treturn nil\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Enforce the 264-byte cap at the framing boundary and close oversized connections.","Log the declared length when a message seems oversized — a huge value usually means a corrupt length prefix.","Do not concatenate multiple messages into one buffer before decoding.","Forward raw bytes in proxies instead of re-encoding."],"tags":["pgproto3","protocol","decoding","cancel","wire-protocol","validation"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}