plandex-ai/plandex · error
error removing lock file: %v
Error message
error removing lock file: %v
What it means
removeLockFile (app/server/db/git.go:557) removes stale git lock files (index.lock, HEAD.lock) before write operations. This error is returned when os.Remove on the lock file fails for a reason other than the file not existing — e.g. permission denied, the path being a non-empty directory, or the file being held in use on Windows. It aborts the lock-cleanup retry loop immediately rather than retrying, since retries won't fix a filesystem-level refusal.
Source
Thrown at app/server/db/git.go:579
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("error checking lock file: %v", err)
}
attempts := 0
for exists {
if attempts > 10 {
return fmt.Errorf("error removing index.lock file: %v after %d attempts", err, attempts)
}
log.Printf("[Git] removeLockFile - removing index.lock file: %s, attempt: %d", lockFilePath, attempts)
if err := os.Remove(lockFilePath); err != nil {
if os.IsNotExist(err) {
log.Printf("[Git] removeLockFile - %s file not found, skipping removal", lockFilePath)
return nil
}
return fmt.Errorf("error removing lock file: %v", err)
}
_, err = os.Stat(lockFilePath)
exists = err == nil
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("error checking lock file: %v", err)
}
log.Printf("[Git] removeLockFile - after removal, %s file exists: %t", lockFilePath, exists)
if exists {
log.Printf("[Git] removeLockFile - %s file still exists, retrying after delay", lockFilePath)
} else {
log.Printf("[Git] removeLockFile - %s file removed successfully", lockFilePath)
return nil
}
attempts++View on GitHub (pinned to e2d772072e)
Solutions
- Fix filesystem permissions on the .git directory: chown -R the app user or chmod u+w on the lock file and parent dir.
- Check the wrapped %v error: EACCES/EPERM -> permissions, EBUSY -> another process holds it, stop competing processes.
- If the repo dir is on a read-only mount, remount read-write or relocate the repo.
- As a last resort for a truly stale lock, delete it manually with elevated privileges, then re-run the operation.
Example fix
// before
if err := os.Remove(lockFilePath); err != nil {
return fmt.Errorf("error removing lock file: %v", err)
}
// after: check writability before calling git operations
if info, err := os.Stat(repoDir + "/.git"); err == nil && info.Mode().Perm()&0200 == 0 {
os.Chmod(repoDir+"/.git", 0755) // or chown to the service user
} Defensive patterns
Strategy: try-catch
Validate before calling
lp := filepath.Join(repoDir, ".git", "index.lock")
if fi, err := os.Stat(lp); err == nil {
if err := syscall.Access(filepath.Dir(lp), syscall.W_OK); err != nil {
return fmt.Errorf("cannot remove %s: no write permission on %s", lp, filepath.Dir(lp))
}
_ = fi
} Type guard
func isRemovableLockErr(err error) bool {
return err != nil && !os.IsNotExist(err)
} Try / catch
err := gitCommit(repoDir, msg)
if err != nil && strings.Contains(err.Error(), "error removing lock file") {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {
return fmt.Errorf("fix .git ownership: chown -R %s %s/.git", user, repoDir)
}
return err
} Prevention
- Run the app under the same user that owns the repo's .git directory.
- Never clone or init repos with sudo while the service runs as another user.
- Avoid read-only or flaky network mounts for active repositories.
- On Windows, exclude .git from antivirus real-time locking during writes.
When it happens
Trigger: Called via gitRemoveIndexLockFileIfExists from gitAdd, gitCommit, gitCheckoutBranch, gitWriteOperation, or lockRepoDB when a lock file exists and os.Remove fails with a non-ENOENT error (e.g. EACCES, EPERM, EISDIR).
Common situations: Repo .git directory owned by a different user (repo cloned with sudo, app running as another user); read-only mounted volume; Windows antivirus or another process briefly holding the file; permissions broken by a container image copy.
Related errors
- error getting git root: %s
- error getting files in git repo: %s
- error walking directory: %s
- failed to check if %s exists: %s
- failed to read %s: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/784a5fb44021e103.
Report an issue: GitHub.