2

I thought I had found a minor issue in Magit forge, and before reporting a bug I wished to update to the latest version. In the process I seem to have borked my installation.

The value of my package-archives variable is

(("gnu" . "https://elpa.gnu.org/packages/")
 ("melpa-stable" . "http://stable.melpa.org/packages/")
 ("melpa" . "http://melpa.org/packages/"))

and the value of my package-archive-priorities variable is

(("melpa-stable" . 10) ("melpa" . 0))

To reach my current state I ran

  1. M-x package-refresh-packages
  2. M-x package-list-packages
  3. U (mark packages to be updated to the latest version)
  4. x (execute the update)
  5. M-x exit-emacs and start a new one

In trying to get Magit and Forge to work again, I've tried three scenarios:

  1. If I start Emacs with my usual .emacs loaded, and I try to run magit-status, it fails with this message:

    slot-missing: Invalid slot name: "#<forge-database forge-database-1589f0c0434c>", :file
    
  2. If I disable a good chunk of my .emacs, I can start Emacs and can run magit-status in a buffer, getting a display. But when I hit the ' key to start a Forge command, it fails with these two messages:

    Cannot insert ("'" "Forge" forge-dispatch) into magit-dispatch; % not found
    transient-setup: Invalid slot name: "#<forge-database forge-database-158b9206ce84>", :file
    
  3. If I run the command given by M-x magit-emacs-Q-command, I can load and use Magit just fine, but I cannot get forge to load. (It has a ton of additional dependencies.)

My question: How can I get Forge commands working again?

I found two questions that look related, but did not glean any answers there:

Norman Ramsey
  • 1,113
  • 6
  • 13
  • Tangentially, if you track your config in version control you can trivially roll back in situations when you break something. I highly recommend doing that. – phils Oct 13 '21 at 22:32
  • This is the second magit-forge problem reported here in the last couple of days. I would suggest you open an issue at https://github.com/magit/forge/issues. – NickD Oct 14 '21 at 01:23
  • @NickD ironically I got into this mess while preparing to open an issue. – Norman Ramsey Oct 14 '21 at 13:14
  • @phils this would mean the contents of my `~/.emacs.d`? What a good idea! – Norman Ramsey Oct 14 '21 at 13:14
  • Absolutely. Not only does it enable you to roll things back, but you can always clone your config in a known working state. – phils Oct 14 '21 at 13:32
  • @Nickd I just dropped https://github.com/emacscollective/closql/discussions/7 – Norman Ramsey Oct 14 '21 at 14:20
  • @tarsius given https://github.com/emacscollective/closql/discussions/7 I'm bringing you into the loop here. – Norman Ramsey Oct 14 '21 at 14:20

1 Answers1

8

Look at the error message you are given:

slot-missing: Invalid slot name: "#<forge-database forge-database-1589f0c0434c>", :file

It says that some code was operating on an object, which you can see is of type forge-database, and it failed when looking for the slot accessed by the key :file. Apparently forge-databases don’t have a slot called :file, so the question you must ask is “What slots does a forge-database actually have?”

Answering this question is pretty easy in Emacs Lisp. Just go to your *scratch* buffer and run (eieio--class-slots (find-class 'forge-database)). You’ll get a list that looks something like this:

[#s(cl-slot-descriptor process unbound process nil)
 #s(cl-slot-descriptor log-buffer nil (or null buffer) ((:documentation . "Output log (debug).")))
 #s(cl-slot-descriptor finalizer unbound t ((:documentation . "Object returned from `make-finalizer'.")))
 #s(cl-slot-descriptor file unbound (or null string) ((:documentation . "Database file name.")))]

I’ve formatted it for easier reading, which has the effect of lining up the names into a column, but you don’t have to do that manually. You can get a list of the slot names by running:

(mapcar #'cl--slot-descriptor-name
        (eieio--class-slots (find-class 'forge-database)))

This gives me a simple list of slot names: (process log-buffer finalizer file), but notice that none of these exactly match the keyword in the error message, which was :file. I expect that this will match the slot named file, but the author of the forge-database class might have had the bad taste to choose confusing initargs for their class, so we should check:

(eieio--class-initarg-tuples (find-class 'forge-database))

Running this gives me a short list:

((:process . process)
 (:log-buffer . log-buffer)
 (:file . file))

It’s pretty clear that when we initialize an instance of class forge-database using the initarg :file, it is supposed to store the value in the slot named file. This is where you are getting the error. You should run the same diagnostic steps in your own Emacs, to see where the difference is. It sounds to me like your version of the Forge library has a different name for the slot, and your version of Magit has not been updated to match. I happen to know that forge-database does not define the file slot directly; it gets it from a base class of a base class. That grandbase class comes from a library for accessing sqlite databases.

It is very probable that you have installed an incompatible version of that sqlite library, either too new or too old. It has a different author than Forge and Magit, so there is no reason to expect them to update in sync with each other. If this proves to be the case, then you could ask the author of either the sqlite or Forge packages which version you should install, or you could examine their history to find when they changed and how, and use that information to pick the correct versions.

db48x
  • 15,741
  • 1
  • 19
  • 23
  • 3
    This is one of the best answers I've ever received on SE. I was today years old when I learned about `eieio` and objects. I have enough to move forward, thanks! – Norman Ramsey Oct 14 '21 at 13:13
  • 1
    Thank you! They’re heavily inspired by the Common Lisp Object System (CLOS) and the Metaobject Protocol (MOP). I recommend reading “The Art of the Metaobject Protocol”, by Kiczales et al, which explains the design rationale behind them. – db48x Oct 14 '21 at 14:43