menu-bar disabled and emacsclient give Error running timer ‘pdf-cache--prefetch-start’
Describe the bug
When the emacs server has the menu bar disabled, opening pdfs gives a Error running timer ‘pdf-cache--prefetch-start’
Steps to Reproduce the behaviour
-
emacs -Q
-
Evaluate
(package-initialize)
(use-package pdf-tools
:init (pdf-loader-install)
:mode (("\\.pdf\\'" . pdf-view-mode)))
(menu-bar-mode -1)
(server-start)
(note: you can disable the menu bar after (server-start); it makes no difference)
emacsclient some_pdf_file.pdf
I get
Error running timer ‘pdf-cache--prefetch-start’: (wrong-type-argument number-or-marker-p nil)
Interestingly, if you don't kill the buffer, and call emacsclient again with the same file, there are no errors. But if you call it on another file, you get the same error.
Enabling the menu bar makes errors go away. Disabling it brings the errors back.
Note that this happens with emacsclient, but not if you simply do:
(package-initialize)
(use-package pdf-tools
:init (pdf-loader-install)
:mode (("\\.pdf\\'" . pdf-view-mode)))
(menu-bar-mode -1)
and open a file. So there is something about the client + lack of menu bar.
What is the expected behaviour? The file is opened without any error
Desktop
- OS: Debian GNU Linux
- Emacs Version: GNU Emacs 30.0.93 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.43, cairo version 1.18.2) of 2024-12-23
- Poppler Version: libpoppler140:amd64 24.08.0-2
Your pdf-tools install
pdf-toolsVersion: pdf-tools-20240429.407 , commit 30b50544e55b8dbf683c2d932d5c33ac73323a16pdf-toolscustomization / configuration that you use: shown above
Additional context
I now (toggle-debug-on-error). This is the output when I call emacsclient:
Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
#f(compiled-function (_) #<bytecode 0x2e6814773c69be7>)(1)
pdf-cache-prefetch-pages-function-default()
pdf-cache--prefetch-start(#<buffer file1.pdf>)
apply(pdf-cache--prefetch-start #<buffer file1.pdf>)
timer-event-handler([t 0 0 500000 t pdf-cache--prefetch-start (#<buffer file1.pdf>) idle 0 nil])
pdf-info-query(number-of-pages "/home/ramon/Downloads/file1.pdf")
pdf-info-number-of-pages()
pdf-cache-number-of-pages()
pdf-view-goto-page(1)
pdf-view-new-window-function((#<window 3 on file1.pdf> (overlay . #<overlay from 1 to 1822728 in file1.pdf>)))
image-mode-winprops(nil t)
image-mode-reapply-winprops()
redisplay_internal\ \(C\ function\)()
Changing the code above to
(use-package pdf-tools
:init (pdf-loader-install)
:mode (("\\.pdf\\'" . pdf-view-mode)))
;; Yes, we could use use-package hook, but for easier reproducibility
(add-hook 'pdf-view-mode-hook (lambda() (pdf-cache-prefetch-minor-mode -1)))
solves the issue. However, this does not seem like a great idea, since caching is disabled.
The following seems like a possible workaround: when we are a client, initially disable prefetching and enable it shortly afterwards. This seems to work for me:
(defun rdu-pdf-cache-disable-enable-in-clients ()
"pdf-cache-prefetch:disable and enable later in clients.
Prevent error message when menu-bar not enabled."
(when (and (daemonp)
(frame-parameter nil 'client))
(pdf-cache-prefetch-minor-mode -1)
(let ((the-buffer (current-buffer)))
(run-with-timer 0.5 nil ;; the 0.5 can be made shorter
(lambda ()
(when (buffer-live-p the-buffer)
(with-current-buffer the-buffer
(when (derived-mode-p 'pdf-view-mode)
(message "Setting pdf-cache-prefetch-minor-mode")
(pdf-cache-prefetch-minor-mode 1)))))))))
(add-hook 'pdf-view-mode-hook #'rdu-pdf-cache-disable-enable-in-clients)
;; or use :hook in use-package
Does this help?
diff --git a/lisp/pdf-cache.el b/lisp/pdf-cache.el
index 9cfb2b9..b9239b8 100644
--- a/lisp/pdf-cache.el
+++ b/lisp/pdf-cache.el
@@ -394,7 +394,7 @@ See also `pdf-info-renderpage-highlight' and
See `pdf-cache-prefetch-pages-function' for an explanation of
what this function does."
- (let ((page (pdf-view-current-page)))
+ (let ((page (or (pdf-view-current-page) 1)))
(pdf-util-remove-duplicates
(cl-remove-if-not
(lambda (page)
From the backtrace, I think what is happening is that cache somehow cache prefetching starts before the current page gets sets. However, I am not sure how client or menu-bar factor into this so this a stab in dim light if not dark.
Thanks. I tried the fix but it does not solve it, though the error message changes:
Error running timer ‘pdf-cache--prefetch-start’: (wrong-type-argument natnum nil page)
With debugging:
Debugger entered--Lisp error: (wrong-type-argument natnum nil page)
pdf-info-pagelinks(nil)
pdf-cache-pagelinks(nil)
pdf-cache-prefetch-pages-function-default()
pdf-cache--prefetch-start(#<buffer file1.pdf>)
apply(pdf-cache--prefetch-start #<buffer file1.pdf>)
timer-event-handler([t 0 0 500000 t pdf-cache--prefetch-start (#<buffer file1.pdf>) idle 0 nil])
pdf-info-query(number-of-pages "/home/ramon/Downloads/file1.pdf")
pdf-info-number-of-pages()
pdf-cache-number-of-pages()
pdf-view-goto-page(1)
pdf-view-new-window-function((#<window 3 on file1.pdf> (overlay . #<overlay from 1 to 1822728 in file1.pdf>)))
image-mode-winprops(nil t)
image-mode-reapply-winprops()
redisplay_internal\ \(C\ function\)()
My wild (and ignorable) guess (elisp newby here) is that the issue arises from the definition of pdf-cache-prefetch-minor-mode that calls pdf-cache--prefetch-start.
And, regardless, this does not explain why menu-bar mode or being run as a client has any effect.
Thanks. I tried the fix but it does not solve it, though the error message changes:
Error running timer ‘pdf-cache--prefetch-start’: (wrong-type-argument natnum nil page)
This is because there are two calls to (pdf-view-current-page) in the pdf-cache-prefetch-pages-function-default. I took care of one but not the other.
With debugging:
Debugger entered--Lisp error: (wrong-type-argument natnum nil page) pdf-info-pagelinks(nil) pdf-cache-pagelinks(nil) pdf-cache-prefetch-pages-function-default() pdf-cache--prefetch-start(#<buffer file1.pdf>) apply(pdf-cache--prefetch-start #<buffer file1.pdf>) timer-event-handler([t 0 0 500000 t pdf-cache--prefetch-start (#<buffer file1.pdf>) idle 0 nil]) pdf-info-query(number-of-pages "/home/ramon/Downloads/file1.pdf") pdf-info-number-of-pages() pdf-cache-number-of-pages() pdf-view-goto-page(1) pdf-view-new-window-function((#<window 3 on file1.pdf> (overlay . #<overlay from 1 to 1822728 in file1.pdf>))) image-mode-winprops(nil t) image-mode-reapply-winprops() redisplay_internal\ \(C\ function\)()My wild (and ignorable) guess (elisp newby here) is that the issue arises from the definition of
pdf-cache-prefetch-minor-modethat callspdf-cache--prefetch-start.And, regardless, this does not explain why menu-bar mode or being run as a client has any effect.
The problem is that the pdf-cache code is written with the assumption that it will always find a current page. In our case this will have happened by the time pdf-view-goto-page returns but hasn't happened yet. What I think the backtrace shows is that this assumption about current page being always set is violated due to the fact that we communicate with epdfinfo server asynchronously. While Emacs is waiting for the response to the query, it turns to doing other stuff like running timers. One of these timers is the one for prefetching cache. So it fires before there is a current page causing the mayhem we see. I think client and the menu bar mode are a red herring in that what they are doing is to somehow add enough delay that the time can fire.
Can you try this,
diff --git a/lisp/pdf-cache.el b/lisp/pdf-cache.el
index 9cfb2b9..0a3eb04 100644
--- a/lisp/pdf-cache.el
+++ b/lisp/pdf-cache.el
@@ -394,7 +394,7 @@ See also `pdf-info-renderpage-highlight' and
See `pdf-cache-prefetch-pages-function' for an explanation of
what this function does."
- (let ((page (pdf-view-current-page)))
+ (when-let ((page (pdf-view-current-page)))
(pdf-util-remove-duplicates
(cl-remove-if-not
(lambda (page)
I think this will solve this particular issue but we assume a current page to be set all over the place and it might still bite us somewhere else. Maybe the better thing will be to set it very early in the body of pdf-view-mode.
Thanks, but it doesn't work.
Debugger entered--Lisp error: (error "epdfinfo: No such page 0")
error("epdfinfo: %s" "No such page 0")
pdf-info-query(pagesize "/home/ramon/Downloads/file1.pdf" nil)
pdf-info-pagesize(nil)
pdf-cache-pagesize(nil)
pdf-view-desired-image-size()
pdf-cache--prefetch-start(#<buffer file1.pdf>)
apply(pdf-cache--prefetch-start #<buffer file1.pdf>)
timer-event-handler([t 0 0 500000 t pdf-cache--prefetch-start (#<buffer file1.pdf>) idle 0 nil])
pdf-info-query(number-of-pages "/home/ramon/Downloads/file1.pdf")
pdf-info-number-of-pages()
pdf-cache-number-of-pages()
pdf-view-goto-page(1)
pdf-view-new-window-function((#<window 3 on file1.pdf> (overlay . #<overlay from 1 to 1822728 in file1.pdf>)))
image-mode-winprops(nil t)
image-mode-reapply-winprops()
redisplay_internal\ \(C\ function\)()
What I find interesting, though, is that no one else seems to have stumbled upon this. And "this" is not that unusual: no menu bar and emacsclient. It is not a fatal error, so I've ignored it (I think for years), so maybe other people have done the same. But still.
Wouldn't it make sense for someone else to make sure this can be reproduced?
Thanks, but it doesn't work.
Debugger entered--Lisp error: (error "epdfinfo: No such page 0") error("epdfinfo: %s" "No such page 0") pdf-info-query(pagesize "/home/ramon/Downloads/file1.pdf" nil) pdf-info-pagesize(nil) pdf-cache-pagesize(nil) pdf-view-desired-image-size() pdf-cache--prefetch-start(#<buffer file1.pdf>) apply(pdf-cache--prefetch-start #<buffer file1.pdf>) timer-event-handler([t 0 0 500000 t pdf-cache--prefetch-start (#<buffer file1.pdf>) idle 0 nil]) pdf-info-query(number-of-pages "/home/ramon/Downloads/file1.pdf") pdf-info-number-of-pages() pdf-cache-number-of-pages() pdf-view-goto-page(1) pdf-view-new-window-function((#<window 3 on file1.pdf> (overlay . #<overlay from 1 to 1822728 in file1.pdf>))) image-mode-winprops(nil t) image-mode-reapply-winprops() redisplay_internal\ \(C\ function\)()
But the error is now inside pdf-cache--prefetch-start so some progress. I am pretty sure this is the function to fix for this particular issue. Can you try this:
diff --git a/lisp/pdf-cache.el b/lisp/pdf-cache.el
index 9cfb2b9..980e4fc 100644
--- a/lisp/pdf-cache.el
+++ b/lisp/pdf-cache.el
@@ -469,6 +469,7 @@ Used solely in `pdf-cache--prefetch-start'.")
(defun pdf-cache--prefetch-start (buffer)
"Start prefetching images in BUFFER."
(when (and pdf-cache-prefetch-minor-mode
+ (pdf-view-current-page)
(not pdf-cache--prefetch-started-p)
(pdf-util-pdf-buffer-p)
(not isearch-mode)
What I find interesting, though, is that no one else seems to have stumbled upon this. And "this" is not that unusual: no menu bar and emacsclient. It is not a fatal error, so I've ignored it (I think for years), so maybe other people have done the same. But still.
Wouldn't it make sense for someone else to make sure this can be reproduced?
I have had this issue but it started happening due to some changes I made in my fork and then it disappeared with further changes. So, I didn't try investigate further. I think this issue is due to timing so it hard to reproduce reliably. Probably a judicious call to sit-for will do it but I will need to familiarize myself with code around pdf-view-mode initialization to figure out where to place it.
If the diff above doesn't work, looking at the initialization code is the only option (please post the new backtrace in that case) but it will take me some time to get to that.
Should I try that change in addition to https://github.com/vedang/pdf-tools/issues/310#issuecomment-2572488191 , or instead of?
Should I try that change in addition to #310 (comment) , or instead of?
Instead of but both should work.
It works! Just the last change (https://github.com/vedang/pdf-tools/issues/310#issuecomment-2580995373) but also the last change plus any one of the two previous attempts ( https://github.com/vedang/pdf-tools/issues/310#issuecomment-2572488191 and https://github.com/vedang/pdf-tools/issues/310#issuecomment-2571682556 ).