Subject: bug#77440: 31.0.50; Error handling for dependencies' default version in package-vc--unpack-1

From: "Yue Yi" <[email-masked]>
Date: Wed, 2 Apr 2025 06:16:30 +0800

Hello Emacs Maintainers, When trying to install code from a repository using `package-vc-install', my Emacs encountered the following error: Debugger entered--Lisp error: (error "Version must be a string")   error("Version must be a string")   version-to-list((0))   (setcar (cdr v) (version-to-list (car (cdr v))))   ......   package-vc--unpack-1(#s(package-desc :name ...)) After some investigation, I found that the issue originates from package-vc.el, starting at line 486 with `threading' and the `callf' below. ;;;; package-vc.el line 486         ......         (thread-last           (mapconcat #'identity require-lines " ")           package-read-from-string           lm--prepare-package-dependencies           (nconc deps)           (setq deps)))))) (dolist (dep deps)   (cl-callf version-to-list (cadr dep))) The issue here is that `lm--prepare-package-dependencies' adds "0" as the default version string when encountering inputs without a version string. However, multiple dependencies will hold an *eq* relationship to the same "0", which means: (setq a (lm--prepare-package-dependencies '(foo bar))) ;;=&gt; ((foo "0") (bar "0")) (let ((print-circle t)) (print a)) ;;=&gt; ((foo . #1=("0")) (bar . #1#)) (setf (cadar a) 'baz) a ;;=&gt; ((foo baz) (bar baz)) To resolve this issue, we can modify the implementation of `lm--prepare-package-dependencies' to return a different short string "0" each time. Alternatively, a simpler approach is to modify `package-vc--unpack-1' so that it retrieves the version string in a non-destructive way. diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el index daceb4eb9c0..b8ed2b8e0e8 100644 --- a/lisp/emacs-lisp/package-vc.el +++ b/lisp/emacs-lisp/package-vc.el @@ -489,8 +489,9 @@ package-vc--unpack-1                  lm--prepare-package-dependencies                  (nconc deps)                  (setq deps)))))) -      (dolist (dep deps) -        (cl-callf version-to-list (cadr dep))) +      (setq deps (mapcar (pcase-lambda (`(,p ,v)) +			   (list p (version-to-list v))) +			 deps))        (setf (package-desc-reqs pkg-desc) deps)        (setf missing (package-vc-install-dependencies (delete-dups deps)))        (setf missing (delq (assq (package-desc-name pkg-desc) Although this issue was discovered during a failed attempt to install a package from GitHub, it can be easily reproduced locally: 1. Create an empty Git repository. 2. Add foo.el with the following content: ;;; foo.el --- Advance `foo-mode' -*- lexical-binding:t; -*- ;; ;; Package-Version: 0.0.1 ;; Package-Requires: (bar) (defun foo-id (x) x) (provide 'foo) ;;; foo.el ends here 3. M-x toggle-debug-on-error to "Debug on Error enabled globally" 4. M-x package-vc-install-from-checkout, select the local git repo's path Then you can see the *Backtrace* information. This bug also occurs in Emacs 30.1. Regards