一句话说明问题:
升级 org-zettel-ref-mode 的数据库格式, 导致加载数据库的函数无法读取正确的数据库. 结果在内存里, 引发了一个错误链. 然而, 报错消息只显示 “let*: End of file during parsing”, 但无具体详细的报告 – 直接误导了问题的解决方向.
辛苦的过程:
由于报错消息直接说明, 代码的括号匹配出问题. 所以一开始是检查代码的括号匹配, 到 Emacs 群里吐槽了一下自己头都要秃了, 顺便把代码发过去请教一下, 高手也回复说是括号匹配. 但括号匹配怎么都查不出问题来, 所以换一个方式, 怀疑 let* 导致了错误的加载. 于是把所有 let* 里引用的变量前面全部都恢复用 let. 报错仍然存在. 整个过程相当令人疲惫.
灵光一闪:
由于之前总结, 如果解决一个 Bug 的方式,重复了 3 次, Bug 依然存在, 那么就要赶紧想想是否别的地方出问题. 不要吊死在一个 Bug 上. 于是, 我想一想, 不妨直接运行导致报错消息的函数试一下看看, 撞大运了, 这一次 Emacs 提供了具体而详细的错误报告. 我终于可以分析问题哪里, 然后顺利解决.
这一个 Bug 出现得很诡异, 它非常隐蔽以后都得注意, 不要导致同样的问题出现.
我让 Claude 帮我解读如下, 问题是数据库格式在我升级了之后, 没有接着升级数据库装载函数, 导致了如下问题, 由于问题存在于内存里, Emacs 未能捕捉到真正的问题:
通过查看错误堆栈和原始函数,我发现问题:
- 错误堆栈顺序:
(let ((data (read (current-buffer)))) ; read 失败,返回 nil
(let ((temp-db (make-hash-table :test 'equal)))
(dolist (entry-data (plist-get data :entries)) ; data 是 nil, plist-get 返回 nil
- 关键问题:
read
函数失败后返回nil
- 但代码继续执行,试图从
nil
中获取:entries
- 而后续函数继续使用这些无效值
最关键的是,这个错误会传递到调用链:
org-zettel-ref-db-load()
-> (let* (...) ...) ; org-zettel-ref-init 中的嵌套 let*
导致 org-zettel-ref-init
中的 let*
无法正常执行,从而引发了 “let*: End of file during parsing” 错误。