hasura/graphql-engine · error

database locked

Error message

database locked

What it means

ErrLocked is returned by Lock() when the migration advisory/consul lock is already held by another client, meaning concurrent migration operations are not possible.

Source

Thrown at cli/migrate/migrate.go:45

	"github.com/hasura/graphql-engine/cli/v2/util"
	log "github.com/sirupsen/logrus"
	"golang.org/x/term"
)

// DefaultPrefetchMigrations sets the number of migrations to pre-read
// from the source. This is helpful if the source is remote, but has little
// effect for a local source (i.e. file system).
// Please note that this setting has a major impact on the memory usage,
// since each pre-read migration is buffered in memory. See DefaultBufferSize.
var DefaultPrefetchMigrations = uint64(10)

// DefaultLockTimeout sets the max time a database driver has to acquire a lock.
var DefaultLockTimeout = 15 * time.Second

var (
	ErrNoChange         = errors.New("no change")
	ErrNilVersion       = errors.New("no migration")
	ErrLocked           = errors.New("database locked")
	ErrNoMigrationFiles = errors.New("no migration files found")
	ErrLockTimeout      = errors.New("timeout: can't acquire database lock")
	ErrApplied          = errors.New("Version already applied in database")
	ErrNotApplied       = errors.New("Migration not applied in database")
	ErrNoMigrationMode  = errors.New("Migration mode is disabled")
	ErrMigrationMode    = errors.New("Migration mode is enabled")
)

const (
	applyingMigrationsMessage = "Applying migrations"
)

func newProgressBar(str string, w io.Writer, pbLogs bool) *pb.ProgressBar { //nolint:unparam
	// Default behaviour in non-interactive mode
	if !pbLogs && !term.IsTerminal(int(os.Stdout.Fd())) {
		return nil
	}
	// bar template configuration

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Find and stop the other process holding the lock, or wait for it to finish
  2. Set an appropriate lock timeout so Lock waits instead of failing fast
  3. Serialize CI/CD migration steps with an external lock or --lock-timeout
Defensive patterns

Strategy: retry

Type guard

func IsLocked(err error) bool { return errors.Is(err, migrate.ErrLocked) }

Try / catch

err := m.Lock()
if err != nil {
    if errors.Is(err, migrate.ErrLocked) { waitAndRetry() }
    return err
}

Prevention

When it happens

Trigger: Calling Lock() (or an operation that acquires it) while another CLI process or server instance holds the migration lock; some drivers return this immediately instead of waiting.

Common situations: Two `hasura migrate apply` runs racing, a hung previous process still holding the lock, CI jobs overlapping on the same server.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/fc392691f035e301. Report an issue: GitHub.