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
- Read the "conn:" and "db:" fields in the message to identify which resource failed; a "<nil>" field means that part succeeded.
- Ensure Close() is called only once per driver instance (migrate instance); guard with sync.Once if teardown may race.
- Check network connectivity/VPN/proxy to the Snowflake account and that the warehouse/session is still alive at shutdown time.
- If the error is benign (session already terminated server-side), log and treat Close failure as non-fatal, since migrations may already be committed.
- 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
- Close each migrate instance exactly once (guard with sync.Once).
- Keep network to Snowflake alive until after Close; don't terminate sessions server-side first.
- Treat teardown errors as non-fatal when migrations have already been committed.
- Keep gosnowflake updated to reduce spurious Close errors.
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.