magit / forge

Work with Git forges from the comfort of Magit
GNU General Public License v3.0
1.32k stars 117 forks source link

Infinite recursion in `forge-get-pullreq` calls in magit status (Lisp nesting exceeds ‘max-lisp-eval-depth’ error) #704

Open mjhoy opened 1 month ago

mjhoy commented 1 month ago

Expected behavior: Opening the magit status buffer for my local repository with a forge database brings me to the status page.

Observed: it fails with the Lisp nesting exceeds ‘max-lisp-eval-depth’ error.

Note: This error was observed with my full configuration loaded. During that emacs session, every time I attempted to load the status buffer it would error consistently. However, when I quit emacs and tried again, it worked. (My plan was to test with my configuration removed except for loading magit.) Feel free to close if you think this is something caused by my setup, I thought I might open the issue just in case it's helpful to track down some kind of non-deterministic bug. I have run into this issue a non-zero number of times in the past six months, although I only just actually tried to debug it.

For context, the repo I had loaded was my dotfiles repo, and the pull request it seems to be recursing on is this one (at the time, the only open PR).

The backtrace is, perhaps obviously, very large. Here is the just the bottom of it (the rest just continues to recurse for many lines):

[..snipped..]
  forge-get-pullreq(259)
  #f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>)(:branch)
  apply(#f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>) :branch nil)
  forge-get-pullreq(:branch)
  forge-topic-at-point()
  forge-repository-at-point()
  #f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>)(:tracked)
  apply(#f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>) :tracked nil)
  forge-get-repository(:tracked)
  #f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>)(259)
  apply(#f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>) 259 nil)
  forge-get-pullreq(259)
  #f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>)(:branch)
  apply(#f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>) :branch nil)
  forge-get-pullreq(:branch)
  forge-topic-at-point()
  forge-repository-at-point()
  #f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>)(:tracked)
  apply(#f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>) :tracked nil)
  forge-get-repository(:tracked)
  #f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>)(259)
  apply(#f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>) 259 nil)
  forge-get-pullreq(259)
  #f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>)(:branch)
  apply(#f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>) :branch nil)
  forge-get-pullreq(:branch)
  forge-topic-at-point()
  forge-repository-at-point()
  #f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>)(:tracked)
  apply(#f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>) :tracked nil)
  forge-get-repository(:tracked)
  #f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>)(259)
  apply(#f(compiled-function (number) #<bytecode -0x11c4eb0b6263b347>) 259 nil)
  forge-get-pullreq(259)
  #f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>)(:branch)
  apply(#f(compiled-function (_ &optional branch) #<bytecode 0x14daf37ca0d0447c>) :branch nil)
  forge-get-pullreq(:branch)
  forge-topic-at-point()
  forge-repository-at-point()
  #f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>)(:tracked?)
  apply(#f(compiled-function (demand &optional remote notatpt) "Return the current forge repository.\n\nFirst check if `forge-buffer-repository', or if that is nil, then\nthe repository for `forge-buffer-topic', satisfies DEMAND.  If so,\nthen return that repository.\n\nOtherwise return the repository for `default-directory', if that\nexists and satisfies DEMAND.  If that fails too, then return nil\nor signal an error, depending on DEMAND." #<bytecode 0x7dd171fce9ee3c4>) :tracked? nil)
  forge-get-repository(:tracked?)
  forge-bug-reference-setup()
  run-hooks(change-major-mode-after-body-hook special-mode-hook magit-section-mode-hook magit-mode-hook magit-status-mode-hook)
  apply(run-hooks (change-major-mode-after-body-hook special-mode-hook magit-section-mode-hook magit-mode-hook magit-status-mode-hook))
  run-mode-hooks(magit-status-mode-hook)
  magit-status-mode()
  magit-setup-buffer-internal(magit-status-mode nil ((magit-buffer-diff-args ("--no-ext-diff")) (magit-buffer-diff-files nil) (magit-buffer-log-args ("-n256" "--decorate")) (magit-buffer-log-files nil)))
  magit-status-setup-buffer("/Users/mjhoy/dotfiles/")
  magit-status("/Users/mjhoy/dotfiles/")
  projectile-vc()
  counsel-projectile-switch-project-by-name("~/dotfiles/")
  counsel-projectile-switch-project-action-vc("~/dotfiles/")
  ivy-call()
  #<subr ivy-read>([..snipped..])
  apply(#<subr ivy-read> [..snipped..])
  ivy-read("[metalstest] Switch to project: " [..snipped..])
  counsel-projectile-switch-project()
  funcall-interactively(counsel-projectile-switch-project)
  command-execute(counsel-projectile-switch-project)

Magit-version: Magit 20240831.2255 [>= 4.1.0], Transient 0.7.5, Forge 0.4.2, Git 2.44.1, Emacs 29.4, darwin

tarsius commented 1 month ago

Forge 0.4.2

Please begin by updating to the latest release or snapshot.

mjhoy commented 1 month ago

@tarsius isn't that the latest release? Am I missing something from the releases page?

tarsius commented 1 month ago

I sometimes forget to update the "Github release thingy" (it's busy work with I should either automate or stop using). The latest release can always be found by looking at what the highest release tag is.

mjhoy commented 1 month ago

I haven't run into this since fetching latest. If it happens again I'll try to do a bit more debugging and comment here but closing this, thanks!

mjhoy commented 1 hour ago

Wanted to reopen as I am still running into this. It seems like there might be some kind of state that causes a cyclic dependency between forge-get-pullreq and forge-get-repository? Running into the same issue now with:

Magit v4.1.2-2-gb2b07b99, Transient 0.7.9, Forge 0.4.4, Git 2.44.1, Emacs 30.0.91, darwin

It happens when I have a branch of a PR checked out, and when I am trying to get back to the magit-status buffer, but it happens very rarely. I am not sure how to debug further, anything I could look at in terms of the state of my repository?