问题描述
在执行 package-refresh-contents 命令时(或者其他命令),经常会出现如下几种错误:
... Failed to download ‘melpa’ archive. ... (wrong-type-argument stringp (require . china-util)) ... (wrong-type-argument stringp (require . info)) ...
问题原因
# 09/12/2020
在使用 edebug 调试后,我们没有找到具体的原因。但是,有时候又能够正常更新,所以,我们猜测是网络原因导致响应内容被破坏而导致失败。
# 01/31/2021
在使用 mitmproxy 抓包后,我们发现响应内容没有问题。
# 03/03/2021
只要把 ~/.emcas 相关的配置移出(备份到其他目录,一切就恢复正常了)。我们又怀疑这个问题与 LC_CTYPE=zh_CN.UTF 环境变量有关。
# 03/04/2021
该错误会导致我们无法通过 Package 安装工具,这是最大的问题。但是,我们找到一个替代方案,来解决无法通过 Package 安装扩展的问题:
1)首先,不加载原有配置,而仅使用自己的配置,来启动:emacs –no-init-file –load init-lite.el
2)而配置文件 init-lite.el 仅包含用于安装扩展的配置:
(setq url-proxy-services '(("http" . "127.0.0.1:8123") ("https" . "127.0.0.1:8123"))) (custom-set-variables '(package-archives '(("gnu" . "https://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/"))))
3)在安装完成之后,我们再重新启动 emacs 应用即可(应用的安装实际就是下载应用到 ~/.emacs.d/elpa/<package-name>/)。或者,在其他 Emacs 实例中执行:(package-initialize)
# 03/15/2021
在我们开启 debug on error(M-x toggle-debug-on-error [RET])后,再次执行引发错误的命令,我们得到如下信息:
Debugger entered--Lisp error: (wrong-type-argument stringp (require . china-util)) string-match("\\(\\`\\|/\\)ffap\\(\\.elc\\|\\.el\\|\\.so\\)?\\(\\.gz\\)?\\'" (require . china-util)) load-history-filename-element("\\(\\`\\|/\\)ffap\\(\\.elc\\|\\.el\\|\\.so\\)?\\(\\.gz\\)?\\'") eval-after-load("ffap" #f(compiled-function () #<bytecode 0xa15b69>)) byte-code("\300\301\302\"\210\303\304\305\306\307DD\310\311\312\313\314&\7\210\303\315\305\306\316DD\317\311\312\313\314&\7\207" [eval-after-load "ffap" #f(compiled-function () #<bytecode 0xa15b69>) custom-declare-variable python-check-command funcall function #f(compiled-function () #<bytecode 0xa15715>) "Command used to check a Python file." :type string :group python python-check-buffer-name #f(compiled-function () #<bytecode 0xa15721>) "Buffer name used for check commands."] 8) python-mode() set-auto-mode-0(python-mode nil) set-auto-mode() normal-mode(t) after-find-file(nil t) find-file-noselect-1(#<buffer demo.py> "/tmp/demo.py" nil nil "/tmp/demo.py" (2097165 64768)) find-file-noselect("/tmp/demo.py" nil nil t) find-file("/tmp/demo.py" t) funcall-interactively(find-file "/tmp/demo.py" t) call-interactively(find-file nil nil) command-execute(find-file)
查看 load-history-filename-element 函数,我们认为在 load-history 中(变量)包含非字符串类型元素,使用 C-h v load-history 查看该变量,其中确实包含非字符串类型变量:
... Value: (("/tmp/.mount_Emacs-Vf5AbQ/usr/share/emacs/27.1/lisp/cus-edit.elc" (require . cus-face) (require . wid-edit) (require . cus-load) (require . cus-start) custom-mode-map custom-mode-link-map custom-field-keymap (defun . custom-split-regexp-maybe) ...
解决方案
定义 load-history-filename-element 函数(添加类型检查),以覆盖原有定义:
;; 将如下定义,加入 ~/.emacs 或 ~/.emacs.d/init.el 文件 (defun load-history-filename-element (file-regexp) "Get the first elt of `load-history' whose car matches FILE-REGEXP. Return nil if there isn't one." (let* ((loads load-history) (load-elt (and loads (car loads)))) (save-match-data (while (and loads (or (null (car load-elt)) (not (and (stringp (car load-elt)) ; new condition (string-match file-regexp (car load-elt)))))) (setq loads (cdr loads) load-elt (and loads (car loads))))) load-elt))
参考文献
Emacs on Android – org-mode – error – `(wrong-type-argument stringp (require . t-mouse))`