gofr-dev/gofr · error

failed to refresh MongoDB lock: lock lost or stolen

Error message

failed to refresh MongoDB lock: lock lost or stolen

What it means

errMongoLockRefreshFailed indicates the periodic heartbeat renewing the MongoDB migration lock failed because the lock document was lost or taken by another process. The migrator aborts rather than run migrations concurrently without exclusive ownership. It is raised by startRefresh during a long-running migration.

Source

Thrown at pkg/gofr/migration/mongo.go:13

package migration

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"time"

	"gofr.dev/pkg/gofr/container"
)

var errMongoLockRefreshFailed = errors.New("failed to refresh MongoDB lock: lock lost or stolen")

type mongoDS struct {
	container.Mongo
}

type mongoMigrator struct {
	container.Mongo
	migrator
	testInterval time.Duration // Used for testing; if non-zero, overrides defaultRefresh
}

// apply initializes mongoMigrator using the Mongo interface.
func (ds mongoDS) apply(m migrator) migrator {
	return mongoMigrator{
		Mongo:    ds.Mongo,
		migrator: m,
	}
}

View on GitHub (pinned to 187eb24962)

Solutions

  1. Ensure only one migrator instance runs at a time (deployment serialization)
  2. Increase lock TTL or shorten migrations so renewals keep up
  3. Check MongoDB availability and the lock collection contents for stale/competing entries
  4. Re-run the migration once the lock is exclusively held again

Example fix

// before
// two pods both run migrations; second loses lock: failed to refresh MongoDB lock
// after
// serialize: k8s leader election or a single migration job
if !lockHeld(ctx, mongo) { return nil } // only migrate when lock is exclusively held
Defensive patterns

Strategy: retry

Validate before calling

// ensure exclusive ownership before starting
var lockDoc bson.M
err := mongoCollection.FindOne(ctx, bson.M{"_id": "gofr_migrations_lock"}).Decode(&lockDoc)
if err == nil && lockDoc["owner"] != thisInstanceID {
    return errors.New("lock held by another instance")
}

Try / catch

err := migrator.Run(c)
if strings.Contains(err.Error(), "failed to refresh MongoDB lock") {
    // abort migrating concurrently; verify no other instance, then retry
    log.Error("lost mongo lock — another migrator may be running")
    return err // do NOT continue migrations without the lock
}

Prevention

When it happens

Trigger: The background refresh loop fails to update the lock document in MongoDB: the document was deleted, lease expired, or another instance acquired it; the Mongo write matches no documents.

Common situations: Migration exceeds the lock TTL without renewal succeeding; two deployments migrating simultaneously; MongoDB failover mid-migration; manual cleanup of the lock collection.

Related errors


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