This is an automated email from the ASF dual-hosted git repository.

joaoreis pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-gocql-driver.git


The following commit(s) were added to refs/heads/trunk by this push:
     new d79b595f Fix protocol version negotiation issues with v5
d79b595f is described below

commit d79b595f714973de5bbb65bd8fbcf8f0f3747dc2
Author: João Reis <[email protected]>
AuthorDate: Tue Aug 26 17:11:31 2025 +0100

    Fix protocol version negotiation issues with v5
    
    Driver was automatically setting beta flag when using v5 protocol which 
causes issues when trying to connect to Cassandra
    versions that supported beta v5 like 3.11.
    
    Also, this patch makes the protocol version discovery process more 
resilient. Still not a long term solution since long term
    we should make the protocol version negotiation work like in the java 
driver.
    
    Patch by João Reis; reviewed by Lukasz Antoniak for CASSGO-88
---
 CHANGELOG.md |  4 ++++
 conn.go      | 16 +++++++++++++++-
 control.go   | 31 +++++++++++++++++++++++++++----
 frame.go     |  3 ---
 4 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19f353ad..68166e39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -65,6 +65,10 @@ and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
+#### 2.0.0
+
+- Do not set beta protocol flag when using v5 (CASSGO-88)
+
 #### 2.0.0-rc1
 
 - Cassandra version unmarshal fix (CASSGO-49)
diff --git a/conn.go b/conn.go
index 6cfb6fe9..877c2aae 100644
--- a/conn.go
+++ b/conn.go
@@ -1317,7 +1317,21 @@ func (c *Conn) execInternal(ctx context.Context, req 
frameBuilder, tracer Tracer
                defer c.releaseStream(call)
 
                if v := resp.framer.header.version.version(); v != c.version {
-                       return nil, NewErrProtocol("unexpected protocol version 
in response: got %d expected %d", v, c.version)
+                       errProtocol := NewErrProtocol("unexpected protocol 
version in response: got %d expected %d", v, c.version)
+                       responseFrame, err := resp.framer.parseFrame()
+                       if err != nil {
+                               c.logger.Warning("Framer error while attempting 
to parse potential protocol error.",
+                                       newLogFieldError("err", err))
+                               return nil, errProtocol
+                       }
+                       //goland:noinspection GoTypeAssertionOnErrors
+                       errFrame, isErrFrame := responseFrame.(errorFrame)
+                       if !isErrFrame || errFrame.Code() != ErrCodeProtocol {
+                               return nil, errProtocol
+                       }
+                       return nil, NewErrProtocol("%w", &protocolError{
+                               errFrame,
+                       })
                }
 
                return resp.framer, nil
diff --git a/control.go b/control.go
index b521c41d..e3c835b4 100644
--- a/control.go
+++ b/control.go
@@ -204,13 +204,34 @@ func shuffleHosts(hosts []*HostInfo) []*HostInfo {
 
 // this is going to be version dependant and a nightmare to maintain :(
 var protocolSupportRe = regexp.MustCompile(`the lowest supported version is 
\d+ and the greatest is (\d+)$`)
+var betaProtocolRe = regexp.MustCompile(`Beta version of the protocol used 
\(.*\), but USE_BETA flag is unset`)
 
 func parseProtocolFromError(err error) int {
+       errStr := err.Error()
+
+       var errProtocol ErrProtocol
+       if errors.As(err, &errProtocol) {
+               err = errProtocol.error
+       }
+
        // I really wish this had the actual info in the error frame...
-       matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1)
+       matches := betaProtocolRe.FindAllStringSubmatch(errStr, -1)
+       if len(matches) == 1 {
+               var protoErr *protocolError
+               if errors.As(err, &protoErr) {
+                       version := protoErr.frame.Header().version.version()
+                       if version > 0 {
+                               return int(version - 1)
+                       }
+               }
+               return 0
+       }
+
+       matches = protocolSupportRe.FindAllStringSubmatch(errStr, -1)
        if len(matches) != 1 || len(matches[0]) != 2 {
-               if verr, ok := err.(*protocolError); ok {
-                       return int(verr.frame.Header().version.version())
+               var protoErr *protocolError
+               if errors.As(err, &protoErr) {
+                       return int(protoErr.frame.Header().version.version())
                }
                return 0
        }
@@ -223,11 +244,13 @@ func parseProtocolFromError(err error) int {
        return max
 }
 
+const highestProtocolVersionSupported = 5
+
 func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) {
        hosts = shuffleHosts(hosts)
 
        connCfg := *c.session.connCfg
-       connCfg.ProtoVersion = 5 // TODO: define maxProtocol
+       connCfg.ProtoVersion = highestProtocolVersionSupported
 
        handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) {
                // we should never get here, but if we do it means we connected 
to a
diff --git a/frame.go b/frame.go
index 93af2c67..7e551c23 100644
--- a/frame.go
+++ b/frame.go
@@ -393,9 +393,6 @@ func newFramer(compressor Compressor, version byte, r 
*RegisteredTypes) *framer
        if compressor != nil {
                flags |= flagCompress
        }
-       if version == protoVersion5 {
-               flags |= flagBetaProtocol
-       }
 
        version &= protoVersionMask
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to