{"id":"b235112579240332","repo":"jackc/pgx","slug":"secret-key-too-long","errorCode":null,"errorMessage":"secret key too long","messagePattern":"secret key too long","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgproto3/cancel_request.go","lineNumber":45,"sourceCode":"\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\")\n\t}\n\tmsgLen := int32(12 + len(src.SecretKey))\n\tdst = pgio.AppendInt32(dst, msgLen)\n\tdst = pgio.AppendInt32(dst, cancelRequestCode)\n\tdst = pgio.AppendUint32(dst, src.ProcessID)\n\tdst = append(dst, src.SecretKey...)\n\treturn dst, nil\n}\n\n// MarshalJSON implements encoding/json.Marshaler.\nfunc (src CancelRequest) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(struct {\n\t\tType      string\n\t\tProcessID uint32\n\t\tSecretKey string\n\t}{\n\t\tType:      \"CancelRequest\",\n\t\tProcessID: src.ProcessID,","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgproto3/cancel_request.go#L27-L63","documentation":"Returned by CancelRequest.Encode when SecretKey is longer than 256 bytes. The wire format reserves a single byte for nothing and the server caps the secret key at 256 bytes, so the library refuses to emit a message the server would reject or misparse. This is a caller-side construction error, not a network problem.","triggerScenarios":"Calling `(*CancelRequest).Encode(dst)` on a struct where `len(SecretKey) > 256`. The real PostgreSQL secret key is exactly 4 bytes (a uint32), so any large slice indicates a caller bug.","commonSituations":"A caller copies the entire BackendKeyData or a full process credential blob into SecretKey instead of the 4-byte secret key returned by the server in the BackendKeyData message. Also seen in test code that stuffs an arbitrary token into the field.","solutions":["Set SecretKey to the 4-byte secret key from the server's BackendKeyData message (the SecretKey field on pgproto3.BackendKeyData), nothing larger.","Validate before encoding: `if len(req.SecretKey) > 256 { return ... }` (or, more correctly, assert it is 4 bytes).","Double-check you did not assign ProcessID or a PID slice into SecretKey by mistake.","If you need a larger cancel token, that is not supported by the PostgreSQL wire protocol — redesign the caller."],"exampleFix":"// before\nreq := &pgproto3.CancelRequest{\n    ProcessID: backendKey.ProcessID,\n    SecretKey: fullBackendKeyBytes, // 8 bytes, wrong\n}\n_, err := req.Encode(nil)\n\n// after\nreq := &pgproto3.CancelRequest{\n    ProcessID: backendKey.ProcessID,\n    SecretKey: mustSecretKey(backendKey.SecretKey), // exactly 4 bytes\n}\n_, err := req.Encode(nil)","handlingStrategy":"validation","validationCode":"func validateCancelRequestEncode(req *pgproto3.CancelRequest) error {\n\tif len(req.SecretKey) > 256 {\n\t\treturn fmt.Errorf(\"secret key too long: %d bytes (max 256)\", len(req.SecretKey))\n\t}\n\treturn nil\n}\n\n// also assert the realistic 4-byte key from BackendKeyData:\n// req.SecretKey must come from backendKeyData.SecretKey (4 bytes)","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always source SecretKey from the server's BackendKeyData.SecretKey (a 4-byte uint32), not an arbitrary token.","Validate struct fields before Encode rather than relying on the encoder to reject them.","Unit-test the encode path with boundary-length secret keys (0, 4, 255, 256, 257)."],"tags":["pgproto3","protocol","encoding","cancel","wire-protocol","validation"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}