Skip to main content
GoodFirstPicks
DashboardIssuesReposLeaderboard

GoodFirstPicks by Leaveitblank © 2026

CreatorRequest a RepoPrivacy PolicyTerms of Service
Module Profile fixture import causes DocumentLockedError on migration retry | GoodFirstPicks

Module Profile fixture import causes DocumentLockedError on migration retry

frappe/frappe 0 comments 1mo ago
View on GitHub
mediumopenScope: clearSkill match: maybeFrappe / ERPNextPython

Why this is a good first issue

The issue involves handling background jobs and document locks during migration.

AI Summary

The issue occurs when a Module Profile fixture import during migration creates a document lock that persists if migration fails, blocking subsequent attempts. The fix involves modifying the condition for synchronous job execution to include migration and fixture flags. The challenge lies in ensuring the lock is properly handled during migration retries.

Issue Description

Description

When a Module Profile document is imported via fixtures during bench migrate, the on_update hook queues a background job (update_all_users) with a document lock. If migration fails after the lock is created but before the job completes, the lock file persists and blocks subsequent migration attempts with DocumentLockedError.

Steps to Reproduce

  1. Create a Frappe app with a Module Profile fixture in fixtures/module_profile.json
  2. Run bench migrate
  3. Force a failure during migration (e.g., another fixture fails validation)
  4. Retry bench migrate

Expected Behavior

Migration should complete successfully on retry.

Actual Behavior

Migration fails with:

frappe.exceptions.DocumentLockedError

The lock file ({sha224_hash}.lock) created during the first attempt persists because the background job never completed.

Root Cause Analysis

In frappe/core/doctype/module_profile/module_profile.py:

def on_update(self):
    self.clear_cache()
    self.queue_action(
        "update_all_users",
        now=frappe.flags.in_test or frappe.flags.in_install,
        enqueue_after_commit=True,
    )

The now parameter only checks in_test and in_install flags. During sync_fixtures():

  • frappe.flags.in_fixtures = True is set (in fixtures.py)
  • frappe.flags.in_migrate = True is set (in migrate.py)
  • But frappe.flags.in_install is NOT set

So the condition evaluates to False, causing the job to be queued asynchronously instead of running synchronously.

The queue_action() method in document.py creates a lock file BEFORE calling enqueue(). If migration fails after lock creation, the lock persists (with a 3-hour expiry via DOCUMENT_LOCK_EXPIRY).

Proposed Fix

Add in_migrate and in_fixtures flags to the condition:

run_now = (
    frappe.flags.in_test
    or frappe.flags.in_install
    or frappe.flags.in_migrate
    or frappe.flags.in_fixtures
)
self.queue_action(
    "update_a

Want to work on this?

Claim this issue to let others know you're working on it. You'll earn 10 points when you complete it!

Risk Flags

  • background job handling
  • lock file persistence
Loading labels...

Details

Points10 pts
Difficultymedium
Scopeclear
Skill Matchmaybe
Test Focusedno