gofr-dev/gofr · error

failed to acquire migration lock

Error message

failed to acquire migration lock

What it means

errLockAcquisitionFailed is returned by lock() when the distributed lock (Redis key gofr_migrations_lock) cannot be acquired before running migrations. This prevents concurrent instances from migrating the same datastore simultaneously. It usually means another process holds the lock or the lock store is unavailable.

Source

Thrown at pkg/gofr/migration/migration.go:19

package migration

import (
	"context"
	"errors"
	"reflect"
	"sort"
	"time"

	"github.com/gogo/protobuf/sortkeys"
	"github.com/google/uuid"
	goRedis "github.com/redis/go-redis/v9"

	"gofr.dev/pkg/gofr/container"
	gofrSql "gofr.dev/pkg/gofr/datasource/sql"
)

var (
	errLockAcquisitionFailed = errors.New("failed to acquire migration lock")
	errLockReleaseFailed     = errors.New("failed to release migration lock")
)

const (
	// lockKey is the key used for distributed locking.
	lockKey = "gofr_migrations_lock"

	// Default values for configuration.
	defaultRetry = 500 * time.Millisecond
	// defaultLockTTL is the duration for which the migration lock is valid.
	// It is kept at 15 seconds to provide a safety margin for network jitters or transient failures.
	defaultLockTTL = 15 * time.Second
	// defaultRefresh is the interval at which the migration lock is renewed.
	// A 5-second interval allows for up to 2 failed refresh attempts before the 15-second TTL expires,
	// ensuring the lock stays robust while still allowing fairly quick recovery if a process crashes.
	defaultRefresh = 5 * time.Second
)

View on GitHub (pinned to 187eb24962)

Solutions

  1. Confirm no other migration is currently running (check lock owner/TTL on gofr_migrations_lock)
  2. If the lock is stale (crashed holder), delete the key or wait for TTL expiry
  3. Verify Redis connectivity and auth in container config
  4. Re-run migrations once the lock is free

Example fix

// before
redis-cli SET gofr_migrations_lock 1 NX // keeps failing: key held by crashed pod
// after
redis-cli DEL gofr_migrations_lock // remove stale lock, then rerun migration
Defensive patterns

Strategy: retry

Validate before calling

// check the lock is free before attempting
n, _ := redisClient.Exists(ctx, "gofr_migrations_lock").Result()
if n == 1 { return errors.New("another migration is in progress; wait or clear stale lock") }

Try / catch

err := migrator.Run(c)
if errors.Is(err, migration.ErrLockAcquisitionFailed) {
    // wait and retry with backoff until the holder finishes or TTL expires
    time.Sleep(10 * time.Second)
    return migrator.Run(c)
}

Prevention

When it happens

Trigger: Another app instance holds gofr_migrations_lock; SETNX fails because the key exists; Redis client error while attempting to set the lock key.

Common situations: Multiple pods deployed and one crashed without releasing the lock (stale lock); Redis misconfigured/unreachable; long-running migration overlapping a deployment.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/0db579d8e0ec91c9. Report an issue: GitHub.