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

  1. 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.
  2. If decoding manually, guard with `if len(src) < 12 { /* short read / partial frame, keep reading or report upstream */ }` before calling Decode.
  3. 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).
  4. 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

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


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/6f34d0ace3233a25.json. Report an issue: GitHub.