jackc/pgx · error
cancel request too short
Error message
cancel request too short
What it means
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.
Source
Thrown at pgproto3/cancel_request.go:24
"encoding/json"
"errors"
"github.com/jackc/pgx/v5/internal/pgio"
)
const cancelRequestCode = 80877102
type CancelRequest struct {
ProcessID uint32
SecretKey []byte
}
// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (*CancelRequest) Frontend() {}
func (dst *CancelRequest) Decode(src []byte) error {
if len(src) < 12 {
return errors.New("cancel request too short")
}
if len(src) > 264 {
return errors.New("cancel request too long")
}
requestCode := binary.BigEndian.Uint32(src)
if requestCode != cancelRequestCode {
return errors.New("bad cancel request code")
}
dst.ProcessID = binary.BigEndian.Uint32(src[4:])
dst.SecretKey = make([]byte, len(src)-8)
copy(dst.SecretKey, src[8:])
return nil
}
// Encode encodes src into dst. dst will include the 4 byte message length.View on GitHub (pinned to ec1a0befd2)
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.
Example fix
// before
var cr pgproto3.CancelRequest
err := cr.Decode(buf) // buf came from an incomplete read → error
// after
if len(buf) < 12 {
return fmt.Errorf("incomplete frame: got %d bytes, need >=12", len(buf))
}
var cr pgproto3.CancelRequest
err := cr.Decode(buf) Defensive patterns
Strategy: validation
Validate before calling
func validateCancelRequestBody(src []byte) error {
if len(src) < 12 {
return fmt.Errorf("cancel request body too short: %d bytes (need >=12)", len(src))
}
return nil
}
// usage before Decode:
if err := validateCancelRequestBody(body); err != nil { return err }
var cr pgproto3.CancelRequest
return cr.Decode(body) Type guard
null
Try / catch
null
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- cancel request too long
- bad cancel request code
- secret key too long
- gss encoding request too short
- too many column format codes
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/6f34d0ace3233a25.json.
Report an issue: GitHub.