{"id":"f21337a7d4e58ce3","repo":"jackc/pgx","slug":"channel-binding-required-but-channel-binding-data","errorCode":null,"errorMessage":"channel binding required but channel binding data is not available","messagePattern":"channel binding required but channel binding data is not available","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgconn/auth_scram.go","lineNumber":72,"sourceCode":"\t// If we have a TLS connection and channel binding is not disabled, attempt to\n\t// extract the server certificate hash for tls-server-end-point channel binding.\n\tif tlsConn, ok := c.conn.(*tls.Conn); ok && c.config.ChannelBinding != \"disable\" {\n\t\tcertHash, err := getTLSCertificateHash(tlsConn)\n\t\tif err != nil && c.config.ChannelBinding == \"require\" {\n\t\t\treturn fmt.Errorf(\"channel binding required but failed to get server certificate hash: %w\", err)\n\t\t}\n\n\t\t// Upgrade to SCRAM-SHA-256-PLUS if we have binding data and the server supports it.\n\t\tif certHash != nil && serverHasPlus {\n\t\t\tsc.authMechanism = scramSHA256PlusName\n\t\t}\n\n\t\tsc.channelBindingData = certHash\n\t\tsc.hasTLS = true\n\t}\n\n\tif c.config.ChannelBinding == \"require\" && sc.channelBindingData == nil {\n\t\treturn errors.New(\"channel binding required but channel binding data is not available\")\n\t}\n\n\t// Send client-first-message in a SASLInitialResponse\n\tsaslInitialResponse := &pgproto3.SASLInitialResponse{\n\t\tAuthMechanism: sc.authMechanism,\n\t\tData:          sc.clientFirstMessage(),\n\t}\n\tc.frontend.Send(saslInitialResponse)\n\terr = c.flushWithPotentialWriteReadDeadlock()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Receive server-first-message payload in an AuthenticationSASLContinue.\n\tsaslContinue, err := c.rxSASLContinue()\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/auth_scram.go#L54-L90","documentation":"Returned by (*PgConn).scramAuth when Config.ChannelBinding == \"require\" but sc.channelBindingData is still nil after the TLS branch. Channel binding data is the server certificate hash obtained via getTLSCertificateHash; if the connection is not TLS or the hash could not be derived, requiring binding is impossible, so the client aborts rather than silently authenticating without the protection the caller asked for.","triggerScenarios":"Config.ChannelBinding == \"require\" on a plaintext connection (no TLS), or on a TLS connection where getTLSCertificateHash failed non-fatally (certHash nil and ChannelBinding != \"require\" path left it nil). Most directly: requiring channel binding over a non-TLS socket.","commonSituations":"Forgetting sslmode/SSL when ChannelBinding=\"require\"; mismatched expectations where ops set ChannelBinding=require but the deployment uses plaintext internal transport.","solutions":["Enable TLS on the connection (sslmode=require/verify-ca/verify-full) so a server certificate hash can be derived.","If TLS is genuinely unavailable, relax Config.ChannelBinding to \"\" or \"disable\".","Verify the server presents a certificate whose signature algorithm is supported by getTLSCertificateHash (RSA/ECDSA SHA-256/384/512)."],"exampleFix":"// before: channel binding required over plaintext\ncc.ChannelBinding = \"require\"\n// conn string has sslmode=disable\n\n// after: require TLS so binding data is available\ncc.ChannelBinding = \"require\"\n// conn string: sslmode=verify-full","handlingStrategy":"validation","validationCode":"// Ensure TLS is on before requiring channel binding.\nfunc validateBindingNeedsTLS(channelBinding, sslmode string) error {\n    if channelBinding == \"require\" && (sslmode == \"\" || sslmode == \"disable\") {\n        return errors.New(\"ChannelBinding=require needs TLS (sslmode != disable)\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := connect(); err != nil {\n    if strings.Contains(err.Error(), \"channel binding required but channel binding data is not available\") {\n        cc.ChannelBinding = \"\" // relax and retry over the same TLS/non-TLS link\n    }\n}","preventionTips":["Pair ChannelBinding=\"require\" with sslmode=verify-full.","Confirm the server presents a certificate whose signature algorithm getTLSCertificateHash supports.","Don't require binding over plaintext internal links."],"tags":["authentication","scram","channel-binding","tls","security"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}