golang-migrate/migrate · error

unknown lock strategy "%s"

Error message

unknown lock strategy "%s"

What it means

Postgres.Lock acquires a migration lock using the configured LockStrategy. This error is returned from the default branch of the strategy switch when p.config.LockStrategy is neither the advisory-lock nor table-lock strategy, meaning the strategy value is empty or unrecognized.

Source

Thrown at database/pgx/pgx.go:257

func (p *Postgres) 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 *Postgres) Lock() error {
	return database.CasRestoreOnErr(&p.isLocked, false, true, database.ErrLocked, func() error {
		switch p.config.LockStrategy {
		case LockStrategyAdvisory:
			return p.applyAdvisoryLock()
		case LockStrategyTable:
			return p.applyTableLock()
		default:
			return fmt.Errorf("unknown lock strategy \"%s\"", p.config.LockStrategy)
		}
	})
}

func (p *Postgres) Unlock() error {
	return database.CasRestoreOnErr(&p.isLocked, true, false, database.ErrNotLocked, func() error {
		switch p.config.LockStrategy {
		case LockStrategyAdvisory:
			return p.releaseAdvisoryLock()
		case LockStrategyTable:
			return p.releaseTableLock()
		default:
			return fmt.Errorf("unknown lock strategy \"%s\"", p.config.LockStrategy)
		}
	})
}

// https://www.postgresql.org/docs/9.6/static/explicit-locking.html#ADVISORY-LOCKS

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Set LockStrategy to a defined constant: pgx.LockStrategyAdvisory or pgx.LockStrategyTable.
  2. Leave LockStrategy zero/unset only if the library's defaults apply; otherwise always assign a constant, never a raw string.
  3. Print the config value and compare against the exported LockStrategy constants to catch typos.
  4. If accepting user input, validate/parse it into a valid LockStrategy before constructing Config.

Example fix

// before
cfg := &pgx.Config{MigrationsTable: "schema_migrations", LockStrategy: "advisory"}
// after
cfg := &pgx.Config{MigrationsTable: "schema_migrations", LockStrategy: pgx.LockStrategyAdvisory}
Defensive patterns

Strategy: validation

Validate before calling

func validateLockStrategy(s pgx.LockStrategy) error {
    if s != pgx.LockStrategyAdvisory && s != pgx.LockStrategyTable {
        return fmt.Errorf("unsupported lock strategy %q", s)
    }
    return nil
}

Type guard

func isKnownLockStrategy(s pgx.LockStrategy) bool {
    return s == pgx.LockStrategyAdvisory || s == pgx.LockStrategyTable
}

Try / catch

if err := drv.Lock(); err != nil {
    if strings.Contains(err.Error(), "unknown lock strategy") {
        return fmt.Errorf("set Config.LockStrategy to pgx.LockStrategyAdvisory or pgx.LockStrategyTable: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Constructing a pgx Config (or WithInstance/Open path) with LockStrategy set to a value other than pgx.LockStrategyAdvisory or pgx.LockStrategyTable (e.g. an empty string, or a user-supplied string like "advisory" that was never converted to the typed constant) and then calling Lock.

Common situations: Hand-building a Config instead of relying on defaults (zero-value empty string); parsing a user string into LockStrategy without validating against the defined constants; switching from another driver's config struct that names lock strategies differently.

Related errors


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