{"record":{"id":"784a5fb44021e103","repo":"plandex-ai/plandex","slug":"error-removing-lock-file-v","errorCode":null,"errorMessage":"error removing lock file: %v","messagePattern":"error removing lock file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/git.go","lineNumber":579,"sourceCode":"\tif err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"error checking lock file: %v\", err)\n\t}\n\n\tattempts := 0\n\tfor exists {\n\t\tif attempts > 10 {\n\t\t\treturn fmt.Errorf(\"error removing index.lock file: %v after %d attempts\", err, attempts)\n\t\t}\n\n\t\tlog.Printf(\"[Git] removeLockFile - removing index.lock file: %s, attempt: %d\", lockFilePath, attempts)\n\n\t\tif err := os.Remove(lockFilePath); err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\tlog.Printf(\"[Git] removeLockFile - %s file not found, skipping removal\", lockFilePath)\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error removing lock file: %v\", err)\n\t\t}\n\n\t\t_, err = os.Stat(lockFilePath)\n\t\texists = err == nil\n\n\t\tif err != nil && !os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"error checking lock file: %v\", err)\n\t\t}\n\n\t\tlog.Printf(\"[Git] removeLockFile - after removal, %s file exists: %t\", lockFilePath, exists)\n\t\tif exists {\n\t\t\tlog.Printf(\"[Git] removeLockFile - %s file still exists, retrying after delay\", lockFilePath)\n\t\t} else {\n\t\t\tlog.Printf(\"[Git] removeLockFile - %s file removed successfully\", lockFilePath)\n\t\t\treturn nil\n\t\t}\n\n\t\tattempts++","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/git.go#L561-L597","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nif err := os.Remove(lockFilePath); err != nil {\n    return fmt.Errorf(\"error removing lock file: %v\", err)\n}\n// after: check writability before calling git operations\nif info, err := os.Stat(repoDir + \"/.git\"); err == nil && info.Mode().Perm()&0200 == 0 {\n    os.Chmod(repoDir+\"/.git\", 0755) // or chown to the service user\n}","handlingStrategy":"try-catch","validationCode":"lp := filepath.Join(repoDir, \".git\", \"index.lock\")\nif fi, err := os.Stat(lp); err == nil {\n    if err := syscall.Access(filepath.Dir(lp), syscall.W_OK); err != nil {\n        return fmt.Errorf(\"cannot remove %s: no write permission on %s\", lp, filepath.Dir(lp))\n    }\n    _ = fi\n}","typeGuard":"func isRemovableLockErr(err error) bool {\n    return err != nil && !os.IsNotExist(err)\n}","tryCatchPattern":"err := gitCommit(repoDir, msg)\nif err != nil && strings.Contains(err.Error(), \"error removing lock file\") {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {\n        return fmt.Errorf(\"fix .git ownership: chown -R %s %s/.git\", user, repoDir)\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","filesystem","git","permissions","lock-file"],"backgroundTag":"git-lock-file-removal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}