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
- Confirm no other migration is currently running (check lock owner/TTL on gofr_migrations_lock)
- If the lock is stale (crashed holder), delete the key or wait for TTL expiry
- Verify Redis connectivity and auth in container config
- 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
- Run migrations from a single serialized job (init container / pre-deploy hook)
- Always set a TTL on the lock so crashed holders self-release
- Monitor for stale gofr_migrations_lock keys
- Verify Redis connectivity in config before deploying
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
- failed to release migration lock
- failed to refresh MongoDB lock: lock lost or stolen
- elasticsearch: %w
- failed to record migration: %w
- mongo: %w
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/0db579d8e0ec91c9.
Report an issue: GitHub.