golang-migrate/migrate · error

session is closed

Error message

session is closed

What it means

ErrClosedSession is returned by WithInstance when the provided *gocql.Session has already been closed (session.Closed() is true). The driver needs a live session to query and update the migrations table, so it rejects a closed one instead of failing later with cryptic gocql errors.

Source

Thrown at database/cassandra/cassandra.go:35

func init() {
	db := new(Cassandra)
	database.Register("cassandra", db)
}

var (
	multiStmtDelimiter = []byte(";")

	DefaultMultiStatementMaxSize = 10 * 1 << 20 // 10 MB
)

var DefaultMigrationsTable = "schema_migrations"

var (
	ErrNilConfig     = errors.New("no config")
	ErrNoKeyspace    = errors.New("no keyspace provided")
	ErrDatabaseDirty = errors.New("database is dirty")
	ErrClosedSession = errors.New("session is closed")
)

type Config struct {
	MigrationsTable       string
	KeyspaceName          string
	MultiStatementEnabled bool
	MultiStatementMaxSize int
}

type Cassandra struct {
	session  *gocql.Session
	isLocked atomic.Bool

	// Open and WithInstance need to guarantee that config is never nil
	config *Config
}

func WithInstance(session *gocql.Session, config *Config) (database.Driver, error) {

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Create (or re-create) the gocql session after closing: session, err := cluster.CreateSession() and pass the fresh session to WithInstance.
  2. Reorder code so session.Close() runs only after migrations are done (move defer Close to after migration completion).
  3. Check session.Closed() yourself before calling WithInstance and surface a clear message.

Example fix

// before
session.Close()
driver, err := cassandra.WithInstance(session, cfg)
// after
driver, err := cassandra.WithInstance(session, cfg)
// ... use driver ...
session.Close()
Defensive patterns

Strategy: type-guard

Validate before calling

if session.Closed() {
    return fmt.Errorf("cannot run migrations: gocql session is already closed")
}

Type guard

func sessionAlive(s *gocql.Session) bool { return s != nil && !s.Closed() }

Try / catch

driver, err := cassandra.WithInstance(session, cfg)
if errors.Is(err, cassandra.ErrClosedSession) {
    return fmt.Errorf("session closed before migrations; create it after connection setup")
}

Prevention

When it happens

Trigger: Calling cassandra.WithInstance(session, config) after cluster.Session() result was closed via session.Close(), or reusing a session captured before a shutdown/defer Close ran.

Common situations: defer session.Close() at the top of a function followed by driver setup, application shutdown hooks re-running migrations, or tests sharing a session closed in a previous teardown.

Related errors


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/c64fd3e72d882862. Report an issue: GitHub.