golang-migrate/migrate · warning

conn: %v, db: %v

Error message

conn: %v, db: %v

What it means

Close() on the Snowflake driver closes both the underlying database/sql connection pool and the native gosnowflake connection. If either Close returns an error, the driver combines both messages into a single error via fmt.Errorf("conn: %v, db: %v", connErr, dbErr). Note that a nil error formats as "<nil>", so the message tells you which of the two resources actually failed.

Source

Thrown at database/snowflake/snowflake.go:155

	migrationsTable := purl.Query().Get("x-migrations-table")

	px, err := WithInstance(db, &Config{
		DatabaseName:    database,
		MigrationsTable: migrationsTable,
	})
	if err != nil {
		return nil, err
	}

	return px, nil
}

func (p *Snowflake) Close() error {
	connErr := p.conn.Close()
	dbErr := p.db.Close()
	if connErr != nil || dbErr != nil {
		return fmt.Errorf("conn: %v, db: %v", connErr, dbErr)
	}
	return nil
}

func (p *Snowflake) Lock() error {
	if !p.isLocked.CompareAndSwap(false, true) {
		return database.ErrLocked
	}
	return nil
}

func (p *Snowflake) Unlock() error {
	if !p.isLocked.CompareAndSwap(true, false) {
		return database.ErrNotLocked
	}
	return nil
}

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Read the "conn:" and "db:" fields in the message to identify which resource failed; a "<nil>" field means that part succeeded.
  2. Ensure Close() is called only once per driver instance (migrate instance); guard with sync.Once if teardown may race.
  3. Check network connectivity/VPN/proxy to the Snowflake account and that the warehouse/session is still alive at shutdown time.
  4. If the error is benign (session already terminated server-side), log and treat Close failure as non-fatal, since migrations may already be committed.
  5. Upgrade github.com/snowflakedb/gosnowflake; older versions had spurious Close errors.

Example fix

// before
if err := m.Close(); err != nil {
    log.Fatal(err) // treats any teardown hiccup as fatal
}
// after
if err := m.Close(); err != nil {
    log.Printf("non-fatal close error (migrations already applied): %v", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if m != nil {
    // only close once; use sync.Once in app code
    var once sync.Once
    once.Do(func() { _ = m.Close() })
}

Type guard

func isCloseErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "conn:")
}

Try / catch

if err := m.Close(); err != nil {
    // message is 'conn: %v, db: %v' — <nil> means that part succeeded
    log.Printf("migrate close (non-fatal, migrations persisted): %v", err)
}

Prevention

When it happens

Trigger: Calling database.Driver.Close() (e.g. via migrate.Close()) when p.conn.Close() and/or p.db.Close() returns a non-nil error — typically a network failure talking to Snowflake, an already-closed connection, or a driver-level teardown error.

Common situations: Network blips or firewall drops between the app and the Snowflake account at teardown; closing migrate twice (second Close hits closed connections); Snowflake warehouse/session being terminated server-side before Close; TLS/token expiration mid-session.

Related errors


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