* lisp/org-clock.el (org-clock-kill-emacs-query): Wrap the `org-clock-out'
and `save-buffer' calls in `condition-case', reporting any error instead of
letting it escape the hook.

`org-clock-kill-emacs-query' runs from `kill-emacs-query-functions', where a
non-nil return value is what allows the exit to proceed.  The function ends
with an unconditional t and a comment saying so, but `org-clock-out' is
called without its FAIL-QUIETLY argument, so any error it signals propagates
out of the hook and that t is never reached.  Emacs then refuses to exit.

The error seen in practice is "Clock start time is gone", which
`org-clock-out' signals when `org-clock-marker' no longer sits on its CLOCK
line.  The marker survives ordinary editing, but it does not survive having
the region that contains the CLOCK line replaced wholesale -- `org-sort-entries'
on the clocked tree does this, and so does reverting a buffer whose changed
span brackets the line.  The user is then stuck: answering "yes" at the
prompt fails and cancels the exit, and only answering "no" gets out.

Recipe, in emacs -Q:

    (setq org-clock-persist nil
          org-clock-auto-clock-resolution nil)
    ;; in an Org buffer with a "** TASK banana" heading
    (org-clock-in)
    ;; now invalidate the marker the way a wholesale replacement does
    (let ((text (buffer-string)))
      (erase-buffer)
      (insert "* New heading\n" text))
    (org-clock-kill-emacs-query)   ; => signals, so C-x C-c would be refused

With this change the same recipe returns t and reports "Could not clock out:
Clock start time is gone" in the echo area.

Note this only guarantees that a lost marker cannot trap the user in a
session; it does not attempt to keep the marker in sync, which is the larger
issue behind the "Clock start time is gone" reports going back to 2017.

TINYCHANGE

---
 lisp/org-clock.el | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index 75ecb1b..7c53b52 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -3353,8 +3353,14 @@ This function is added to `kill-emacs-query-functions'."
   (let ((buf (org-clocking-buffer)))
     (when (and buf (yes-or-no-p "Clock out before exiting? "))
       (with-current-buffer buf
-        (org-clock-out)
-        (save-buffer))))
+        ;; Do not let a failure here abort `kill-emacs'.  In particular,
+        ;; `org-clock-marker' may no longer sit on its CLOCK line, and
+        ;; `org-clock-out' then signals "Clock start time is gone".
+        (condition-case err
+            (progn (org-clock-out) (save-buffer))
+          (error
+           (message "Could not clock out: %s" (error-message-string err))
+           (sit-for 2))))))
   ;; Unconditionally return t for `kill-emacs-query-functions'.
   t)
 
-- 
2.44.0


Reply via email to