golang-migrate/migrate · warning

conn: %v, db: %v

Error message

conn: %v, db: %v

What it means

Wraps both errors from closing the SQLServer driver's two underlying connections: ss.conn (the raw database connection) and ss.db (the *sql.DB handle). It fires from Close when either Close call fails, so both underlying failures are reported in one message. Investigate the individual conn/db errors for the root cause, such as connection already closed or network failure.

Source

Thrown at database/sqlserver/sqlserver.go:187

	px, err := WithInstance(db, &Config{
		DatabaseName:    purl.Path,
		MigrationsTable: migrationsTable,
	})

	if err != nil {
		return nil, err
	}

	return px, nil
}

// Close the database connection
func (ss *SQLServer) Close() error {
	connErr := ss.conn.Close()
	dbErr := ss.db.Close()
	if connErr != nil || dbErr != nil {
		return fmt.Errorf("conn: %v, db: %v", connErr, dbErr)
	}
	return nil
}

// Lock creates an advisory local on the database to prevent multiple migrations from running at the same time.
func (ss *SQLServer) Lock() error {
	return database.CasRestoreOnErr(&ss.isLocked, false, true, database.ErrLocked, func() error {
		aid, err := database.GenerateAdvisoryLockId(ss.config.DatabaseName, ss.config.SchemaName)
		if err != nil {
			return err
		}

		// This will block until the lock is acquired.
		// MS Docs: sp_getapplock: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql?view=sql-server-2017
		query := `
		DECLARE @lockResult int;
		EXEC @lockResult = sp_getapplock @Resource = @p1, @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = -1;
		SELECT @lockResult;`

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Inspect the wrapped conn/db messages to see which close failed; usually the connection was already dead and the error is safe to log and ignore
  2. Ensure Close is called exactly once and after migrations finish, not twice on the same instance
  3. Verify network/DB availability before shutdown-time close; re-run migrations only after reconnecting

Example fix

// before
if err := driver.Close(); err != nil { panic(err) }
// after
if err := driver.Close(); err != nil {
    log.Printf("migration driver close failed (may be benign on dead conn): %v", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := driver.Close(); err != nil {
    var conns []string
    if errors.As(err, &wrapped) { /* inspect 'conn:' / 'db:' parts */ }
    log.Printf("sqlserver driver close: %v", err)
}

Prevention

When it happens

Trigger: Calling migrate instance Close while the connection is already broken/closed, or the pool close fails due to network issues or driver state errors.

Common situations: Deferred Close after a migration failure on a dead connection; shutting down an app while the DB server is unavailable; double-closing via both the driver and sql.DB lifecycle management.

Related errors


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