{"id":"6f34d0ace3233a25","repo":"jackc/pgx","slug":"cancel-request-too-short","errorCode":null,"errorMessage":"cancel request too short","messagePattern":"cancel request too short","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgproto3/cancel_request.go","lineNumber":24,"sourceCode":"\t\"encoding/json\"\n\t\"errors\"\n\n\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.","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgproto3/cancel_request.go#L6-L42","documentation":"This error is returned by CancelRequest.Decode when the supplied byte slice is shorter than 12 bytes. A valid PostgreSQL cancel request contains a 4-byte request code, a 4-byte process ID, and at least 4 bytes of secret-key framing, so 12 bytes is the hard floor. The library refuses to read past the end of the buffer rather than returning partially-initialized garbage.","triggerScenarios":"Calling `(*CancelRequest).Decode(src)` (directly or via a Frontend/Receive path on a server-side listener) where `len(src) < 12`. This only happens on the side that *receives* a cancel request — typically a PostgreSQL server, a proxy, or a test harness, not a normal pgx client.","commonSituations":"A truncated packet arrives because the sender was interrupted mid-write, a proxy stripped bytes, or the byte stream being decoded is not actually a cancel request (wrong message routed to the wrong decoder). Also seen when fuzzing or when a hand-rolled test fixture supplies an undersized buffer.","solutions":["Verify the caller is feeding the complete, correctly-framed message body to Decode — the 5-byte header is already stripped by Frontend.Receive, so src must be exactly the body.","If decoding manually, guard with `if len(src) < 12 { /* short read / partial frame, keep reading or report upstream */ }` before calling Decode.","Check that the upstream sender (proxy, pgbouncer, test client) is not truncating the cancel request; a real libpq-style cancel request is at least 16 bytes on the wire (length + code + pid + key).","If you control the sender, ensure it encodes the full 12-byte body: 4-byte code + 4-byte PID + 4-byte secret key minimum."],"exampleFix":"// before\nvar cr pgproto3.CancelRequest\nerr := cr.Decode(buf) // buf came from an incomplete read → error\n\n// after\nif len(buf) < 12 {\n    return fmt.Errorf(\"incomplete frame: got %d bytes, need >=12\", len(buf))\n}\nvar cr pgproto3.CancelRequest\nerr := cr.Decode(buf)","handlingStrategy":"validation","validationCode":"func validateCancelRequestBody(src []byte) error {\n\tif len(src) < 12 {\n\t\treturn fmt.Errorf(\"cancel request body too short: %d bytes (need >=12)\", len(src))\n\t}\n\treturn nil\n}\n\n// usage before Decode:\nif err := validateCancelRequestBody(body); err != nil { return err }\nvar cr pgproto3.CancelRequest\nreturn cr.Decode(body)","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always read the full declared message body before calling Decode; never feed partial reads.","Distinguish the first-int32 magic on a fresh connection before routing to a specific decoder.","In a proxy, enforce min/max body lengths at the framing layer so decoders never see out-of-range inputs.","Fuzz-test your framing code with truncated packets to confirm it reports rather than panics."],"tags":["pgproto3","protocol","decoding","cancel","wire-protocol","validation"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}