Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fatal error: all goroutines are asleep - deadlock! #3880

Open
beetol opened this issue Sep 1, 2024 · 7 comments
Open

fatal error: all goroutines are asleep - deadlock! #3880

beetol opened this issue Sep 1, 2024 · 7 comments
Labels
bug Something isn't working

Comments

@beetol
Copy link

beetol commented Sep 1, 2024

Describe the bug

fatal error: all goroutines are asleep - deadlock!

To Reproduce
Steps to reproduce the behavior (macOS Sonoma latest version, latest go installation from its website):

  1. go install github.com/jesseduffield/lazygit@latest

Expected behavior
Open LazyGit interface

Version info:

lazygit version
commit=, build date=, build source=unknown, version=unversioned, os=darwin, arch=amd64, git version=2.46.0

git version
git version 2.46.0

Additional context
Running on macOS Sonoma 14.6
Have added ~/go/bin to $PATH as instructed.

POTENTIAL DEADLOCK: Recursive locking: when running lazygit --debug

@beetol beetol added the bug Something isn't working label Sep 1, 2024
@stefanhaller
Copy link
Collaborator

Your reproduction recipe shows pretty much basic, normal lazygit usage as far as I can tell. There must be something more that is specific to your setup, otherwise lazygit would be unusable for everybody.

Are you starting lazygit from within a git repo? Does the problem happen for all your repos, or only certain ones? Have you checked if an official build (e.g. the homebrew version) has the same problem?

@beetol
Copy link
Author

beetol commented Sep 2, 2024

Are you starting lazygit from within a git repo?

Yes, a good example is the mantinedev/mantine repo I've cloned. It also happens to one of my own repos.

Have you checked if an official build (e.g. the homebrew version) has the same problem?

Yes, have tried using the Homebrew version and I still get the same error.

On a tangent, with the steps above, I don't get this error on an Apple Silicon. Though when running lazygit --debug, it just hangs without any output.

@RBird111
Copy link

I was looking into #3903 and ran into this issue with a binary compiled from a local checkout. Here's the trace from two different attempts:

Attempt 1

POTENTIAL DEADLOCK: Inconsistent locking. saw this ordering in one goroutine:
happened before
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:442 helpers.(*RefreshHelper).refreshBranches { self.c.Mutexes().RefreshingBranchesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:273 helpers.(*RefreshHelper).refreshReflogAndBranches { self.refreshBranches(refreshWorktrees, keepBranchSelectionIndex, loadBehindCounts) }
pkg/gui/controllers/helpers/refresh_helper.go:129 helpers.(*RefreshHelper).Refresh.func2.2 { if self.c.AppState.LocalBranchSortOrder == "recency" { }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

happened after
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/commands/git_commands/main_branches.go:42 git_commands.(*MainBranches).Get { self.mutex.Lock() }
pkg/commands/git_commands/main_branches.go:56 git_commands.(*MainBranches).GetMergeBase { func (self *MainBranches) GetMergeBase(refName string) string { }
pkg/commands/git_commands/commit_loader.go:105 git_commands.(*CommitLoader).GetCommits.func2 {  }
pkg/utils/utils.go:87 utils.Safe.func1 { func Safe(f func()) { }
pkg/utils/utils.go:98 utils.SafeWithError {  }
pkg/utils/utils.go:88 utils.Safe { _ = SafeWithError(func() error { f(); return nil }) }

in another goroutine: happened before
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/commands/git_commands/main_branches.go:42 git_commands.(*MainBranches).Get { self.mutex.Lock() }
pkg/commands/git_commands/main_branches.go:56 git_commands.(*MainBranches).GetMergeBase { func (self *MainBranches) GetMergeBase(refName string) string { }
pkg/commands/git_commands/commit_loader.go:105 git_commands.(*CommitLoader).GetCommits.func2 {  }
pkg/utils/utils.go:87 utils.Safe.func1 { func Safe(f func()) { }
pkg/utils/utils.go:98 utils.SafeWithError {  }
pkg/utils/utils.go:88 utils.Safe { _ = SafeWithError(func() error { f(); return nil }) }

happened after
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:442 helpers.(*RefreshHelper).refreshBranches { self.c.Mutexes().RefreshingBranchesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:258 helpers.(*RefreshHelper).refreshReflogCommitsConsideringStartup.func1 { self.refreshBranches(false, true, true) }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

Other goroutines holding locks:
goroutine 2 lock 0xc00040bb38
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:512 helpers.(*RefreshHelper).refreshFilesAndSubmodules { self.c.Mutexes().RefreshingFilesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:154 helpers.(*RefreshHelper).Refresh.func2.8 { _ = self.refreshFilesAndSubmodules() }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

goroutine 2 lock 0xc0003d3128
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/commands/git_commands/main_branches.go:42 git_commands.(*MainBranches).Get { self.mutex.Lock() }
pkg/commands/git_commands/main_branches.go:56 git_commands.(*MainBranches).GetMergeBase { func (self *MainBranches) GetMergeBase(refName string) string { }
pkg/commands/git_commands/commit_loader.go:105 git_commands.(*CommitLoader).GetCommits.func2 {  }
pkg/utils/utils.go:87 utils.Safe.func1 { func Safe(f func()) { }
pkg/utils/utils.go:98 utils.SafeWithError {  }
pkg/utils/utils.go:88 utils.Safe { _ = SafeWithError(func() error { f(); return nil }) }

goroutine 2 lock 0xc00040bb50
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:322 helpers.(*RefreshHelper).refreshCommitsWithLimit { self.c.Mutexes().LocalCommitsMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:277 helpers.(*RefreshHelper).refreshCommitsAndCommitFiles { _ = self.refreshCommitsWithLimit() }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

Attempt 2

POTENTIAL DEADLOCK: Recursive locking:
current goroutine 2 lock 0xc00040db40
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:442 helpers.(*RefreshHelper).refreshBranches { self.c.Mutexes().RefreshingBranchesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:258 helpers.(*RefreshHelper).refreshReflogCommitsConsideringStartup.func1 { self.refreshBranches(false, true, true) }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

Previous place where the lock was grabbed (same goroutine)
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:442 helpers.(*RefreshHelper).refreshBranches { self.c.Mutexes().RefreshingBranchesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:273 helpers.(*RefreshHelper).refreshReflogAndBranches { self.refreshBranches(refreshWorktrees, keepBranchSelectionIndex, loadBehindCounts) }
pkg/gui/controllers/helpers/refresh_helper.go:129 helpers.(*RefreshHelper).Refresh.func2.2 { if self.c.AppState.LocalBranchSortOrder == "recency" { }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

Other goroutines holding locks:
goroutine 2 lock 0xc00040db38
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:512 helpers.(*RefreshHelper).refreshFilesAndSubmodules { self.c.Mutexes().RefreshingFilesMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:154 helpers.(*RefreshHelper).Refresh.func2.8 { _ = self.refreshFilesAndSubmodules() }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

goroutine 2 lock 0xc00040db50
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/gui/controllers/helpers/refresh_helper.go:322 helpers.(*RefreshHelper).refreshCommitsWithLimit { self.c.Mutexes().LocalCommitsMutex.Lock() }
pkg/gui/controllers/helpers/refresh_helper.go:277 helpers.(*RefreshHelper).refreshCommitsAndCommitFiles { _ = self.refreshCommitsWithLimit() }
pkg/gui/controllers/helpers/refresh_helper.go:107 helpers.(*RefreshHelper).Refresh.func2.1.1 { f() }
vendor/github.com/jesseduffield/gocui/gui.go:700 gocui.(*Gui).onWorkerAux {  }
vendor/github.com/jesseduffield/gocui/gui.go:688 gocui.(*Gui).OnWorker.func1 { g.onWorkerAux(f, task) }

goroutine 2 lock 0xc00036a568
vendor/github.com/sasha-s/go-deadlock/deadlock.go:85 go-deadlock.(*Mutex).Lock { lock(m.mu.Lock, m) } <<<<<
pkg/commands/git_commands/main_branches.go:42 git_commands.(*MainBranches).Get { self.mutex.Lock() }
pkg/commands/git_commands/main_branches.go:56 git_commands.(*MainBranches).GetMergeBase { func (self *MainBranches) GetMergeBase(refName string) string { }
pkg/commands/git_commands/commit_loader.go:105 git_commands.(*CommitLoader).GetCommits.func2 {  }
pkg/utils/utils.go:87 utils.Safe.func1 { func Safe(f func()) { }
pkg/utils/utils.go:98 utils.SafeWithError {  }
pkg/utils/utils.go:88 utils.Safe { _ = SafeWithError(func() error { f(); return nil }) }

For what it's worth, this was only when running a locally compiled version: commit=a04ad24a60584135e94a7eb2ff32c956e1e5a83d, build date=2024-09-18T11:26:47Z, build source=unknown, version=a04ad24a, os=linux, arch=amd64, git version=2.34.1

The downloaded version runs fine: commit=2d0c7cb0fc85e3c262837eb9691813fa97e00e80, build date=2024-09-07T02:26:26Z, build source=binaryRelease, version=0.44.0, os=linux, arch=amd64, git version=2.34.1

@canton7
Copy link

canton7 commented Sep 27, 2024

I've just seen this after a clean clone of the lazygit repo, setting up the devcontainer, then running go run main.go -debug from within the devcontainer. It also doesn't work in the codespace recommended in CONTRIBUTING.md.

However, it doesn't happen without -debug.

I also can't run any of the integration tests, which is making contributing something somewhat challenging...

@canton7
Copy link

canton7 commented Sep 29, 2024

FWIW, deadlock.Opts.DisableLockOrderDetection = true at the top of NewGui disables that error, so at least you can run the tests. I had a flick through the code it was unhappy about, and couldn't spot anything wrong.

@phanirithvij
Copy link
Contributor

#4002

@ChrisMcD1
Copy link
Contributor

Potentially connected to sasha-s/go-deadlock#38

stefanhaller added a commit that referenced this issue Feb 10, 2025
- **PR Description**

This PR solves #4002, and
perhaps #3880 (if they
are indeed duplicates), and the error message preventing debugging in
#3973.

The problem is that our version of `go-deadlock` transitively depends on
a version of `goid` that predates their changes to support go `1.23`,
which results in every goid being the number `2` for some reason.
Bumping the version of `go-deadlock` to include the updated transitive
dependency means that the goids are now correct, and `go-deadlock` does
not confused why goroutine 2 is trying to lock so many things.

I know very little about go vendored dependencies, so all I have done is
edit the `go.mod` entry for `go-deadlock` to be v0.3.5, and then run a
`go mod tidy` and `go mod vendor`. If there is a more correct way to
bump a vendored dependency, feel free to close this PR and just do that!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants