{"record":{"id":"a4aea64a30abd56d","repo":"gofr-dev/gofr","slug":"failed-to-refresh-mongodb-lock-lock-lost-or-stole","errorCode":null,"errorMessage":"failed to refresh MongoDB lock: lock lost or stolen","messagePattern":"failed to refresh MongoDB lock: lock lost or stolen","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/migration/mongo.go","lineNumber":13,"sourceCode":"package migration\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gofr.dev/pkg/gofr/container\"\n)\n\nvar errMongoLockRefreshFailed = errors.New(\"failed to refresh MongoDB lock: lock lost or stolen\")\n\ntype mongoDS struct {\n\tcontainer.Mongo\n}\n\ntype mongoMigrator struct {\n\tcontainer.Mongo\n\tmigrator\n\ttestInterval time.Duration // Used for testing; if non-zero, overrides defaultRefresh\n}\n\n// apply initializes mongoMigrator using the Mongo interface.\nfunc (ds mongoDS) apply(m migrator) migrator {\n\treturn mongoMigrator{\n\t\tMongo:    ds.Mongo,\n\t\tmigrator: m,\n\t}\n}","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/migration/mongo.go#L1-L31","documentation":"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.","triggerScenarios":"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.","commonSituations":"Migration exceeds the lock TTL without renewal succeeding; two deployments migrating simultaneously; MongoDB failover mid-migration; manual cleanup of the lock collection.","solutions":["Ensure only one migrator instance runs at a time (deployment serialization)","Increase lock TTL or shorten migrations so renewals keep up","Check MongoDB availability and the lock collection contents for stale/competing entries","Re-run the migration once the lock is exclusively held again"],"exampleFix":"// before\n// two pods both run migrations; second loses lock: failed to refresh MongoDB lock\n// after\n// serialize: k8s leader election or a single migration job\nif !lockHeld(ctx, mongo) { return nil } // only migrate when lock is exclusively held","handlingStrategy":"retry","validationCode":"// ensure exclusive ownership before starting\nvar lockDoc bson.M\nerr := mongoCollection.FindOne(ctx, bson.M{\"_id\": \"gofr_migrations_lock\"}).Decode(&lockDoc)\nif err == nil && lockDoc[\"owner\"] != thisInstanceID {\n    return errors.New(\"lock held by another instance\")\n}","typeGuard":null,"tryCatchPattern":"err := migrator.Run(c)\nif strings.Contains(err.Error(), \"failed to refresh MongoDB lock\") {\n    // abort migrating concurrently; verify no other instance, then retry\n    log.Error(\"lost mongo lock — another migrator may be running\")\n    return err // do NOT continue migrations without the lock\n}","preventionTips":["Run only one migrator instance per datastore (leader election / single job)","Size lock TTL above worst-case migration duration with renewals","Monitor MongoDB failovers during deploy windows","Never ignore lock-refresh failures — concurrent migrations corrupt history"],"tags":["mongodb","migration","distributed-lock"],"backgroundTag":"lock-refresh-failed","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}