{"record":{"id":"16b523a5cbb73058","repo":"t8y2/dbx","slug":"cassandra-connection-runtime-is-closed","errorCode":null,"errorMessage":"Cassandra connection runtime is closed","messagePattern":"Cassandra connection runtime is closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/cassandra-go/runtime.go","lineNumber":57,"sourceCode":"\tconfig, err := parseCassandraConfig(cp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpoolSize := runtimePoolSize()\n\treturn &connectionRuntime{\n\t\tconfig:          config,\n\t\tsessions:        map[string]*gocql.Session{},\n\t\tpermits:         make(chan struct{}, poolSize),\n\t\tmetadataPermits: make(chan struct{}, runtimeMetadataLimit(poolSize)),\n\t}, nil\n}\n\nfunc (r *connectionRuntime) sessionFor(keyspace string) (*gocql.Session, error) {\n\tkeyspace = strings.TrimSpace(keyspace)\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tif r.closed {\n\t\treturn nil, errors.New(\"Cassandra connection runtime is closed\")\n\t}\n\tif session := r.sessions[keyspace]; session != nil && !session.Closed() {\n\t\treturn session, nil\n\t}\n\tcluster, err := r.config.clusterConfig(keyspace)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsession, err := cluster.CreateSession()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr.sessions[keyspace] = session\n\treturn session, nil\n}\n\nfunc (r *connectionRuntime) invalidateMetadataSession() {\n\tvar retiredSession *gocql.Session","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/cassandra-go/runtime.go#L39-L75","documentation":"sessionFor guards access to the connection runtime's gocql sessions. If the runtime has been closed (e.g. after Close was called or connection teardown), any attempt to obtain a session returns this error instead of lazily creating a new one.","triggerScenarios":"Calling validateConnection, connectionInfo, allKeyspaceMetadata, keyspaceMetadata, querySystemIndexes, or listTriggers after the connectionRuntime was closed via its Close method.","commonSituations":"Race between a shutdown/close and in-flight or queued queries; background metadata refreshers running after disconnect; clients holding a driver handle past connection close and issuing more RPCs.","solutions":["Reopen the connection before issuing further RPCs","Stop background workers/metadata refreshers when the runtime is closed","Check runtime liveness (or a closed flag exposed by the client) before calling session-dependent methods","Fix lifecycle ordering so Close happens only after all operations complete (sync.WaitGroup / context cancellation)"],"exampleFix":"// before\n// rows := rpc(\"execute_query\", opts) // runtime already closed\n// after\n// if !conn.IsOpen() { conn = reconnect() }\n// rows := rpc(\"execute_query\", opts)","handlingStrategy":"try-catch","validationCode":"// only issue RPCs while the connection is known open\nif (!conn.isOpen()) { conn = await reconnect(); }","typeGuard":"func (c *Client) runtimeOpen() bool {\n  c.mu.Lock(); defer c.mu.Unlock()\n  return c.runtime != nil && !c.runtime.closed\n}","tryCatchPattern":"rows, err := rpcSessionCall(...)\nif err != nil && strings.Contains(err.Error(), \"connection runtime is closed\") {\n  conn = reconnect()\n  rows, err = rpcSessionCall(...) // single retry after reopen\n}","preventionTips":["Cancel background refreshers before calling Close on the runtime","Serialize shutdown: wait for in-flight ops (WaitGroup) then close","Track connection state client-side and refuse RPCs after close","Reconnect transparently on this error for long-lived processes"],"tags":["cassandra","lifecycle","closed-connection","rpc","session"],"backgroundTag":"connection-closed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}