Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capture template 'X': Wrong type argument: stringp, nil #4832

Closed
erikc96 opened this issue Mar 21, 2021 · 18 comments
Closed

Capture template 'X': Wrong type argument: stringp, nil #4832

erikc96 opened this issue Mar 21, 2021 · 18 comments
Labels
is:bug Something isn't working as intended module:lang/org Pertains to Doom's :lang org module status:resolved Issue was addressed internally status:unknown Cause unknown; cannot be reproduced; cannot investigate further

Comments

@erikc96
Copy link

erikc96 commented Mar 21, 2021

Can't use any capture templates! Found this thread[0], other people are having the same issue. Other person experiencing this was told to make a new issue but I couldn't find it, so I'm making this one.

  1. org-capture: Capture abort: Wrong type argument: stringp, nil #2923

What did you expect to happen?
My capture template to work normally.

What actually happened?
I got an error saying that the wrong sort of arguments were being passed:

Capture template 'X': Wrong type argument: stringp, nil

Steps to reproduce:
Run any capture template

System information:
https://pastebin.com/DcgZFF08

@ineu
Copy link
Contributor

ineu commented Mar 28, 2021

Happens for me as well. Introduced in 9f08db8
For me it only happens

  1. For custom templates (I overwrite org-capture-templates) and
  2. If org-capture is called after invoking the agenda view. If I start emacs, run org-capture, then run org-agenda and then org-capture again, then captures work

@vinurs

This comment has been minimized.

@pinacle2000
Copy link

I have the same problem, whenever I open org-agenda, i.e. org-agenda searched/opened org buffers backend. I can only make org-caputre work again by SPC-b-K, i.e. kill all bufer.

@dorneanu

This comment has been minimized.

@IsaacDempsey
Copy link

Had the same issue. I find it only happens if I haven't yet opened the buffer I'm capturing to. Once the buffer is open, capture works correctly.

@harveyr
Copy link

harveyr commented Apr 14, 2021

Thanks @IsaacDempsey. I had a hunch I could fix it by opening that buffer and possibly editing/saving it. But I haven't had a chance to prove it.

@hlissner
Copy link
Member

hlissner commented Apr 14, 2021

I cannot reproduce this. With or without an existing destination org file, with any of the default capture templates, on 26.3, 27.1, 27.2 or 28 (native-comp), on NixOS, Arch Linux, or MacOS (Big Sur).

  1. Please show me your value for org-capture-templates and the code you're using to set it.
  2. Please produce a backtrace from the error
  3. Please don't flood this (or any other) issue with "Same problem here"'s unless you have something more to add. Click the 👍 emoji on the original post instead.
  4. Please make sure Doom is up-to-date when you test again.

@hlissner hlissner added module:lang/org Pertains to Doom's :lang org module status:unknown Cause unknown; cannot be reproduced; cannot investigate further labels Apr 14, 2021
@critbase
Copy link

i get this error too, here's my config and backtrace

  1. org-capture-templates (i didn't include all of mine as a few are quite personal)
(after! org
  (setq
        org-capture-templates
        '(
          ; other entries here
          ("t" "tasks" entry
           (file+olp+datetree "journal.org")
           "* TODO %?\n%U"))))
  1. backtrace:
Debugger entered--Lisp error: (error "Capture template ‘t’: Wrong type argument: stringp...")
  error("Capture template `%s': %s" "t" "Wrong type argument: stringp, nil")
  #f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x5b4e76bfd41a2b4>)(nil)
  apply(#f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x5b4e76bfd41a2b4>) nil)
  (let ((+file-templates-inhibit t)) (apply orig-fn args))
  +file-templates-inhibit-in-org-capture-a(#f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x5b4e76bfd41a2b4>) nil)
  apply(+file-templates-inhibit-in-org-capture-a #f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x5b4e76bfd41a2b4>) nil)
  org-capture(nil)
  #<subr funcall-interactively>(org-capture nil)
  apply(#<subr funcall-interactively> (org-capture nil))
  funcall-interactively(org-capture nil)
  #<subr call-interactively>(org-capture nil nil)
  apply(#<subr call-interactively> (org-capture nil nil))
  explain-pause--wrap-call-interactively(#<subr call-interactively> org-capture nil nil)
  apply(explain-pause--wrap-call-interactively #<subr call-interactively> (org-capture nil nil))
  call-interactively(org-capture nil nil)
  command-execute(org-capture)

@Thrimbda
Copy link

Met the same error, here's my config and backtrace, I suspect it was something related to the agenda:

  1. backtrace
Debugger entered--Lisp error: (error "Capture template ‘t’: Wrong type argument: stringp...")
  error("Capture template `%s': %s" "t" "Wrong type argument: stringp, nil")
  #<subr org-capture>(nil)
  apply(#<subr org-capture> nil)
  (let ((+file-templates-inhibit t)) (apply orig-fn args))
  +file-templates-inhibit-in-org-capture-a(#<subr org-capture> nil)
  apply(+file-templates-inhibit-in-org-capture-a #<subr org-capture> nil)
  org-capture(nil)
  funcall-interactively(org-capture nil)
  command-execute(org-capture)
  1. capture-template, I've adopted Bernt Hansen's config:
(setq org-capture-templates
      (quote (("t" "todo" entry (file "~/OneDrive/cone/refile.org")
               "* TODO %?\n%U\n%a\n" :clock-in t :clock-resume t)
              ("r" "respond" entry (file "~/OneDrive/cone/refile.org")
               "* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n" :clock-in t :clock-resume t :immediate-finish t)
              ("n" "note" entry (file "~/OneDrive/cone/refile.org")
               "* %? :NOTE:\n%U\n%a\n" :clock-in t :clock-resume t)
              ("b" "book" entry (file "~/OneDrive/cone/books.org")
               "* TODO Read %? :BOOK:\n%U" :clock-in t :clock-resume t)
              ("j" "Journal" entry (file+olp+datetree "~/OneDrive/cone/diary.org")
               "* %?\n%U\n" :clock-in t :clock-resume t)
              ("w" "org-protocol" entry (file "~/OneDrive/cone/refile.org")
               "* TODO Review %c\n%U\n" :immediate-finish t)
              ("m" "Meeting" entry (file "~/OneDrive/cone/refile.org")
               "* MEETING with %? :MEETING:\n%U" :clock-in t :clock-resume t)
              ("p" "Phone call" entry (file "~/OneDrive/cone/refile.org")
               "* PHONE %? :PHONE:\n%U" :clock-in t :clock-resume t)
              ("h" "Habit" entry (file "~/OneDrive/cone/refile.org")
               "* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"%<<%Y-%m-%d %a .+1d/3d>>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n"))))

@Zweihander-Main
Copy link

Zweihander-Main commented Apr 16, 2021

  1. Backtrace (from SPC-n-i i):
Debugger entered--Lisp error: (error "Capture template ‘i’: Wrong type argument: stringp...")
  signal(error ("Capture template ‘i’: Wrong type argument: stringp..."))
  error("Capture template `%s': %s" "i" "Wrong type argument: stringp, nil")
  #f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x15702c8deb95>)(nil)
  apply(#f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x15702c8deb95>) nil)
  (let ((+file-templates-inhibit t)) (apply orig-fn args))
  +file-templates-inhibit-in-org-capture-a(#f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof the day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x15702c8deb95>) nil)
  apply(+file-templates-inhibit-in-org-capture-a #f(compiled-function (&optional goto keys) "Capture something.\n\\<org-capture-mode-map>\nThis will let you select a template from `org-capture-templates', and\nthen file the newly captured information.  The text is immediately\ninserted at the target location, and an indirect buffer is shown where\nyou can edit it.  Pressing `\\[org-capture-finalize]' brings you back to the previous\nstate of Emacs, so that you can continue your work.\n\nWhen called interactively with a `\\[universal-argument]' prefix argument GOTO, don't\ncapture anything, just go to the file/headline where the selected\ntemplate stores its notes.\n\nWith a `\\[universal-argument] \\[universal-argument]' prefix argument, go to the last note stored.\n\nWhen called with a `C-0' (zero) prefix, insert a template at point.\n\nWhen called with a `C-1' (one) prefix, force prompting for a date when\na datetree entry is made.\n\nELisp programs can set KEYS to a string associated with a template\nin `org-capture-templates'.  In this case, interactive selection\nwill be bypassed.\n\nIf `org-capture-use-agenda-date' is non-nil, capturing from the\nagenda will use the date at point as the default date.  Then, a\n`C-1' prefix will tell the capture process to use the HH:MM time\nof te day at point (if any) or the current HH:MM time." (interactive "P") #<bytecode 0x15702c8deb95>) nil)
  org-capture(nil)
  funcall-interactively(org-capture nil)
  call-interactively(org-capture nil nil)
  command-execute(org-capture)
  1. I can get the error to occur consistently using the following fairly minimal snippet:
(setq org-capture-templates
      `(("i" "inbox"
         entry
         (file "/home/zwei/org/gtd/inbox.org")
         "* ")))

Steps to reproduce:

  1. Open emacs
  2. Open an agenda view (SPC-o-a-a a using the default Agenda but any custom agenda command appears to have the same effect)
  3. Open a capture SPC-n-i i. Error occurs without a capture buffer visibly opening.
  4. Open the file in question (in this case, inbox.org)
  5. Open a capture SPC-n-i i. Error no longer occurs. Subsequent opens of agenda don't have any effect.

The above steps also work in the same manner when using other files ie using a next.org file and related capture template.

If a capture template is opened before any agenda is ever opened, the error usually doesn't occur (but behaviour may be inconsistent in that case -- won't swear to it but I think it once gave me the error in this case awhile back).

Misc eval and message info:

Don't know if this is any help but I tried to figure out what was happening in the org-capture function that was causing problems which led me down this dubiously relevant path:

; 1. 
(org-capture nil "i")

; 2. org-capture.el 692
(org-capture-place-template nil)

; 3. org.capture.el 1121
(org-switch-to-buffer-other-window
   (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE"))

; 4. org-macs.el 234
(switch-to-buffer-other-window
   (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE"))

; 5. window.el.gz 8516
(pop-to-buffer (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE") t)

; 6. window.el.gz 8249
(display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t)

; 7. from the below backtrace
(+org--restart-mode-h)

The above 7 eval snippets all produce the same message (wrong-type-argument stringp nil) under the error conditions. They appear to work or give something along the lines of "The base buffer has disappeared" when the error conditions don't occur.

  1. results in the following backtrace:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  expand-file-name(nil)
  find-file-noselect(nil nil nil nil)
  find-file(nil)
  (let ((file buffer-file-name) (inhibit-redisplay t)) (kill-buffer) (find-file file))
  +org--restart-mode-h()
  run-hooks(doom-switch-buffer-hook)
  (save-current-buffer (set-buffer (if (windowp buffer) (window-buffer buffer) buffer)) (run-hooks 'doom-switch-buffer-hook))
  (progn (save-current-buffer (set-buffer (if (windowp buffer) (window-buffer buffer) buffer)) (run-hooks 'doom-switch-buffer-hook)) buffer)
  (if buffer (progn (save-current-buffer (set-buffer (if (windowp buffer) (window-buffer buffer) buffer)) (run-hooks 'doom-switch-buffer-hook)) buffer) nil)
  (let* ((buffer (and t (apply orig-fn buffer-or-name args)))) (if buffer (progn (save-current-buffer (set-buffer (if (windowp buffer) (window-buffer buffer) buffer)) (run-hooks 'doom-switch-buffer-hook)) buffer) nil))
  (let ((gc-cons-threshold most-positive-fixnum) (doom-inhibit-switch-buffer-hooks t) (inhibit-redisplay t)) (let* ((buffer (and t (apply orig-fn buffer-or-name args)))) (if buffer (progn (save-current-buffer (set-buffer (if (windowp buffer) (window-buffer buffer) buffer)) (run-hooks 'doom-switch-buffer-hook)) buffer) nil)))
  (if (or doom-inhibit-switch-buffer-hooks (and buffer-or-name (eq (current-buffer) (get-buffer buffer-or-name))) (and (eq orig-fn #'switch-to-buffer) (car args))) (apply orig-fn buffer-or-name args) (let ((gc-cons-threshold most-positive-fixnum) (doom-inhibit-switch-buffer-hooks t) (inhibit-redisplay t)) (let* ((buffer (and t (apply orig-fn buffer-or-name args)))) (if buffer (progn (save-current-buffer (set-buffer (if ... ... buffer)) (run-hooks 'doom-switch-buffer-hook)) buffer) nil))))
  doom-run-switch-buffer-hooks-a(#f(compiled-function (buffer-or-name &optional action frame) "Display BUFFER-OR-NAME in some window, without selecting it.\nBUFFER-OR-NAME must be a buffer or a string naming a live buffer.\nReturn the window chosen for displaying that buffer, or nil if no\nsuch window is found.\n\nOptional argument ACTION, if non-nil, should specify a buffer\ndisplay action of the form (FUNCTIONS . ALIST).  FUNCTIONS is\neither an \"action function\" or a possibly empty list of action\nfunctions.  ALIST is a possibly empty \"action alist\".\n\nAn action function is a function that accepts two arguments: the\nbuffer to display and an action alist.  Based on those arguments,\nit should try to display the buffer in a window and return that\nwindow.  An action alist is an association list mapping symbols\nto values.  Action functions use the action alist passed to them\nto fine-tune their behaviors.\n\n`display-buffer' builds a list of action functions and an action\nalist by combining any action functions and alists specified by\n`display-buffer-overriding-action', `display-buffer-alist', the\nACTION argument, `display-buffer-base-action', and\n`display-buffer-fallback-action' (in order).  Then it calls each\nfunction in the combined function list in turn, passing the\nbuffer as the first argument and the combined action alist as the\nsecond argument, until one of the functions returns non-nil.\n\nAction functions and the action they try to perform are:\n `display-buffer-same-window' -- Use the selected window.\n `display-buffer-reuse-window' -- Use a window already showing\n    the buffer.\n `display-buffer-in-previous-window' -- Use a window that did\n    show the buffer before.\n `display-buffer-use-some-window' -- Use some existing window.\n `display-buffer-pop-up-window' -- Pop up a new window.\n `display-buffer-below-selected' -- Use or pop up a window below\n    the selected one.\n `display-buffer-at-bottom' -- Use or pop up a window at the\n    bottom of the selected frame.\n `display-buffer-pop-up-frame' -- Show the buffer on a new frame.\n `display-buffer-in-child-frame' -- Show the buffer in a\n    child frame.\n `display-buffer-no-window' -- Do not display the buffer and\n    have `display-buffer' return nil immediately.\n\nAction alist entries are:\n `inhibit-same-window' -- A non-nil value prevents the same\n    window from being used for display.\n `inhibit-switch-frame' -- A non-nil value prevents any frame\n    used for showing the buffer from being raised or selected.\n `reusable-frames' -- The value specifies the set of frames to\n    search for a window that already displays the buffer.\n    Possible values are nil (the selected frame), t (any live\n    frame), visible (any visible frame), 0 (any visible or\n    iconified frame) or an existing live frame.\n `pop-up-frame-parameters' -- The value specifies an alist of\n    frame parameters to give a new frame, if one is created.\n `window-height' -- The value specifies the desired height of the\n    window chosen and is either an integer (the total height of\n    the window), a floating point number (the fraction of its\n    total height with respect to the total height of the frame's\n    root window) or a function to be called with one argument -\n    the chosen window.  The function is supposed to adjust the\n    height of the window; its return value is ignored.  Suitable\n    functions are `shrink-window-if-larger-than-buffer' and\n    `fit-window-to-buffer'.\n `window-width' -- The value specifies the desired width of the\n    window chosen and is either an integer (the total width of\n    the window), a floating point number (the fraction of its\n    total width with respect to the width of the frame's root\n    window) or a function to be called with one argument - the\n    chosen window.  The function is supposed to adjust the width\n    of the window; its return value is ignored.\n `preserve-size' -- The value should be either (t . nil) to\n    preserve the width of the chosen window, (nil . t) to\n    preserve its height or (t . t) to preserve its height and\n    width in future changes of the window configuration.\n `window-parameters' -- The value specifies an alist of window\n    parameters to give the chosen window.\n `allow-no-window' -- A non-nil value means that `display-buffer'\n    may not display the buffer and return nil immediately.\n\nThe entries `window-height', `window-width' and `preserve-size'\nare applied only when the window used for displaying the buffer\nnever showed another buffer before.\n\nThe ACTION argument can also have a non-nil and non-list value.\nThis means to display the buffer in a window other than the\nselected one, even if it is already displayed in the selected\nwindow.  If called interactively with a prefix argument, ACTION\nis t.  Non-interactive calls should always supply a list or nil.\n\nThe optional third argument FRAME, if non-nil, acts like a\n(reusable-frames . FRAME) entry appended to the action alist\nspecified by the ACTION argument." ... #<bytecode 0x1ffca034ccb1>) #<killed buffer> t)
  apply(doom-run-switch-buffer-hooks-a #f(compiled-function (buffer-or-name &optional action frame) "Display BUFFER-OR-NAME in some window, without selecting it.\nBUFFER-OR-NAME must be a buffer or a string naming a live buffer.\nReturn the window chosen for displaying that buffer, or nil if no\nsuch window is found.\n\nOptional argument ACTION, if non-nil, should specify a buffer\ndisplay action of the form (FUNCTIONS . ALIST).  FUNCTIONS is\neither an \"action function\" or a possibly empty list of action\nfunctions.  ALIST is a possibly empty \"action alist\".\n\nAn action function is a function that accepts two arguments: the\nbuffer to display and an action alist.  Based on those arguments,\nit should try to display the buffer in a window and return that\nwindow.  An action alist is an association list mapping symbols\nto values.  Action functions use the action alist passed to them\nto fine-tune their behaviors.\n\n`display-buffer' builds a list of action functions and an action\nalist by combining any action functions and alists specified by\n`display-buffer-overriding-action', `display-buffer-alist', the\nACTION argument, `display-buffer-base-action', and\n`display-buffer-fallback-action' (in order).  Then it calls each\nfunction in the combined function list in turn, passing the\nbuffer as the first argument and the combined action alist as the\nsecond argument, until one of the functions returns non-nil.\n\nAction functions and the action they try to perform are:\n `display-buffer-same-window' -- Use the selected window.\n `display-buffer-reuse-window' -- Use a window already showing\n    the buffer.\n `display-buffer-in-previous-window' -- Use a window that did\n    show the buffer before.\n `display-buffer-use-some-window' -- Use some existing window.\n `display-buffer-pop-up-window' -- Pop up a new window.\n `display-buffer-below-selected' -- Use or pop up a window below\n    the selected one.\n `display-buffer-at-bottom' -- Use or pop up a window at the\n    bottom of the selected frame.\n `display-buffer-pop-up-frame' -- Show the buffer on a new frame.\n `display-buffer-in-child-frame' -- Show the buffer in a\n    child frame.\n `display-buffer-no-window' -- Do not display the buffer and\n    have `display-buffer' return nil immediately.\n\nAction alist entries are:\n `inhibit-same-window' -- A non-nil value prevents the same\n    window from being used for display.\n `inhibit-switch-frame' -- A non-nil value prevents any frame\n    used for showing the buffer from being raised or selected.\n `reusable-frames' -- The value specifies the set of frames to\n    search for a window that already displays the buffer.\n    Possible values are nil (the selected frame), t (any live\n    frame), visible (any visible frame), 0 (any visible or\n    iconified frame) or an existing live frame.\n `pop-up-frame-parameters' -- The value specifies an alist of\n    frame parameters to give a new frame, if one is created.\n `window-height' -- The value specifies the desired height of the\n    window chosen and is either an integer (the total height of\n    the window), a floating point number (the fraction of its\n    total height with respect to the total height of the frame's\n    root window) or a function to be called with one argument -\n    the chosen window.  The function is supposed to adjust the\n    height of the window; its return value is ignored.  Suitable\n    functions are `shrink-window-if-larger-than-buffer' and\n    `fit-window-to-buffer'.\n `window-width' -- The value specifies the desired width of the\n    window chosen and is either an integer (the total width of\n    the window), a floating point number (the fraction of its\n    total width with respect to the width of the frame's root\n    window) or a function to be called with one argument - the\n    chosen window.  The function is supposed to adjust the width\n    of the window; its return value is ignored.\n `preserve-size' -- The value should be either (t . nil) to\n    preserve the width of the chosen window, (nil . t) to\n    preserve its height or (t . t) to preserve its height and\n    width in future changes of the window configuration.\n `window-parameters' -- The value specifies an alist of window\n    parameters to give the chosen window.\n `allow-no-window' -- A non-nil value means that `display-buffer'\n    may not display the buffer and return nil immediately.\n\nThe entries `window-height', `window-width' and `preserve-size'\nare applied only when the window used for displaying the buffer\nnever showed another buffer before.\n\nThe ACTION argument can also have a non-nil and non-list value.\nThis means to display the buffer in a window other than the\nselected one, even if it is already displayed in the selected\nwindow.  If called interactively with a prefix argument, ACTION\nis t.  Non-interactive calls should always supply a list or nil.\n\nThe optional third argument FRAME, if non-nil, acts like a\n(reusable-frames . FRAME) entry appended to the action alist\nspecified by the ACTION argument." ... #<bytecode 0x1ffca034ccb1>) (#<killed buffer> t))
  display-buffer(#<killed buffer> t)
  eval((display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t) t)
  #f(compiled-function (exp &optional insert-value no-truncate char-print-limit) "Evaluate EXP and print value in the echo area.\nWhen called interactively, read an Emacs Lisp expression and\nevaluate it.  Value is also consed on to front of the variable\n`values'.  Optional argument INSERT-VALUE non-nil (interactively,\nwith a non `-' prefix argument) means insert the result into the\ncurrent buffer instead of printing it in the echo area.\n\nNormally, this function truncates long output according to the\nvalue of the variables `eval-expression-print-length' and\n`eval-expression-print-level'.  When NO-TRUNCATE is\nnon-nil (interactively, with a prefix argument of zero), however,\nthere is no such truncation.\n\nIf the resulting value is an integer, and CHAR-PRINT-LIMIT is\nnon-nil (interactively, unless given a non-zero prefix argument)\nit will be printed in several additional formats (octal,\nhexadecimal, and character).  The character format is used only\nif the value is below CHAR-PRINT-LIMIT (interactively, if the\nprefix argument is -1 or the value doesn't exceed\n`eval-expression-print-maximum-character').\n\nRuns the hook `eval-expression-minibuffer-setup-hook' on entering the\nminibuffer.\n\nIf `eval-expression-debug-on-error' is non-nil, which is the default,\nthis command arranges for all errors to enter the debugger." (interactive #f(compiled-function () #<bytecode 0x156436f13915>)) #<bytecode 0x1ffca024077b>)((display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t) nil nil 127)
  apply(#f(compiled-function (exp &optional insert-value no-truncate char-print-limit) "Evaluate EXP and print value in the echo area.\nWhen called interactively, read an Emacs Lisp expression and\nevaluate it.  Value is also consed on to front of the variable\n`values'.  Optional argument INSERT-VALUE non-nil (interactively,\nwith a non `-' prefix argument) means insert the result into the\ncurrent buffer instead of printing it in the echo area.\n\nNormally, this function truncates long output according to the\nvalue of the variables `eval-expression-print-length' and\n`eval-expression-print-level'.  When NO-TRUNCATE is\nnon-nil (interactively, with a prefix argument of zero), however,\nthere is no such truncation.\n\nIf the resulting value is an integer, and CHAR-PRINT-LIMIT is\nnon-nil (interactively, unless given a non-zero prefix argument)\nit will be printed in several additional formats (octal,\nhexadecimal, and character).  The character format is used only\nif the value is below CHAR-PRINT-LIMIT (interactively, if the\nprefix argument is -1 or the value doesn't exceed\n`eval-expression-print-maximum-character').\n\nRuns the hook `eval-expression-minibuffer-setup-hook' on entering the\nminibuffer.\n\nIf `eval-expression-debug-on-error' is non-nil, which is the default,\nthis command arranges for all errors to enter the debugger." (interactive #f(compiled-function () #<bytecode 0x1564367f10e1>)) #<bytecode 0x1ffca024077b>) ((display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t) nil nil 127))
  eval-expression((display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t) nil nil 127)
  funcall-interactively(eval-expression (display-buffer (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) t) nil nil 127)
  call-interactively(eval-expression nil nil)
  command-execute(eval-expression)

with (window-normalize-buffer-to-switch-to (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE")) evaluating to #<buffer CAPTURE-10-inbox.org> with the number increasing every time I eval it. If I try and manually select the CAPTURE-n-inbox.org buffers, they pop up no problem.

Update:
Also forgot, inbox.org is part of my org-agenda-files. If I open emacs, then immediately set org-agenda-files to '(), the error condition doesn't appear to occur.

@yangsheng6810
Copy link
Contributor

Spent quite some time, and I think I figured it out what happens.

TLDR:

  1. It is the the fault of +org--restart-mode-h, which does not handles indirect buffers correctly.
  2. One temporary and imperfect workaround could be (this is not well tested, as I cannot reliably re-produce the error):
(use-package org
  :defer t
  :config
  (defalias '+org--restart-mode-h #'ignore))

Note you will need to manually kill the half-broken org buffer to make it look proper.

Backgrounds:

According to the docstring of +org-defer-mode-in-agenda-buffers-h, Doom seem to have incomplete org-mode buffers when calling org-agenda, in order to speed up startup. However, when the user does want to visit those buffers, those are half-broken org buffers. To avoid this, +org--restart-mode-h is added to doom-switch-buffer-hook for every such buffer locally. When the user visits such a buffer, +org--restart-mode-h kills the buffer and re-open it.

What happens:

This should work fine, until we do an org-capture whose target is a file in org-agenda-files. When org-capture is called, e.g. on file "inbox.org", it creates an indirect buffer to buffer "inbox.org", and call it "CAPTURE-inbox.org". When we are about to switch to this prepared indirect buffer, we have the following calling path

  • org-capture
  • org-capture-place-template
  • org-switch-to-buffer-other-window
  • switch-to-buffer-other-window
  • pop-to-buffer
  • display-buffer, where display-buffer is adviced with doom-run-switch-buffer-hooks-a
  • doom-run-switch-buffer-hooks-a runs hook doom-switch-buffer-hook
  • doom-switch-buffer-hook contains +org--restart-mode-h for those org-agenda-files
  • +org--restart-mode-h works on the indirect buffer we are going to switch to, get its file, kill the buffer, and re-open the file.

And here is the definition of +org--restart-mode-h:

  (defun +org--restart-mode-h ()
    "Restart `org-mode', but only once."
    (remove-hook 'doom-switch-buffer-hook #'+org--restart-mode-h
                 'local)
    (delq! (current-buffer) org-agenda-new-buffers)
    (let ((file buffer-file-name)
          (inhibit-redisplay t))
      (kill-buffer)
      (find-file file)))

So "CAPTURE-inbox.org" is killed, and with (find-file "inbox.org"), we open the file "inbox.org". But wait, "CAPTURE-inbox.org" is NO LONGER a live buffer! When doom-run-switch-buffer-hooks-a tries to apply the next function in doom-switch-buffer-hook, that function would assume there is some valid current-buffer, which is no longer true.

This is not the only problem. This no-longer-valid buffer is then returned by doom-run-switch-buffer-hooks-a, which is an around advice on display-buffer. However, display-buffer is supposed to return the WINDOW for the given buffer, not the buffer itself.

Possible fix

We can use the imperfect workaround mentioned earlier, but it disables the automatic reload for half-broken org files. For a better solution, I think we need something like the following (Disclaimer: THIS IS JUST AN IDEA, AND IS NOT TESTED! For a workaround, see the first section TLDR.):

(defun +org--restart-mode-h ()
    "Restart `org-mode', but only once."
    (remove-hook 'doom-switch-buffer-hook #'+org--restart-mode-h
                 'local)
    (delq! (current-buffer) org-agenda-new-buffers)
    (let ((file buffer-file-name)
          (old-buffer (current-buffer))
          (inhibit-redisplay t)
          new-buffer)
      (kill-buffer)
      (setq new-buffer (find-file file))
      (unless (buffer-live-p old-buffer)
        (make-indirect-buffer new-buffer old-buffer 'clone))))

And we also need to fix the return value of doom-run-switch-buffer-hooks-a.

@molekular
Copy link

I can confirm that the workaround @yangsheng6810 suggests does work.

Emacs version: 27.2
Doom: most recent (rcf98c0d8bb)
EXWM
Archlinux

@acosmicjoke
Copy link

I didn't manage to make @yangsheng6810 's second suggestion work, probably because I don't understand how to fix the return value of doom-run-switch-buffer-hooks-a; however, I tweaked the first one a bit with

(advice-add #'org-capture :around
                 (lambda (fun &rest args)
                   (letf! ((#'+org--restart-mode-h #'ignore))
                     (apply fun args))))

and now I can use capture without getting half-broken org buffers. (Not counting the capture buffers themselves that is.)

@pinacle2000
Copy link

Start to getting this message:

condition-case: Error in a Doom startup hook: org-agenda-finalize-hook, +org-defer-mode-in-agenda-buffers-h, (error "Selecting deleted buffer")

It's still about agenda and buffer.

@ineu
Copy link
Contributor

ineu commented May 20, 2021

The initial issue seems to be fixed for me in the latest develop. Not sure if it's caused by the code changes or the dependencies update.

@github-actions
Copy link

github-actions bot commented Aug 1, 2021

This issue has been automatically marked stale because of a lack of recent activity. If this issue is still valid, reply to it or remove the label, or it will be closed in 7 days.

@github-actions github-actions bot added the stale No response, forgotten, or abandoned label Aug 1, 2021
@github-actions github-actions bot closed this as completed Aug 8, 2021
@dukebarman

This comment has been minimized.

@hlissner

This comment has been minimized.

@doomemacs doomemacs locked as resolved and limited conversation to collaborators Oct 5, 2021
@hlissner hlissner added is:bug Something isn't working as intended status:resolved Issue was addressed internally and removed stale No response, forgotten, or abandoned labels Oct 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
is:bug Something isn't working as intended module:lang/org Pertains to Doom's :lang org module status:resolved Issue was addressed internally status:unknown Cause unknown; cannot be reproduced; cannot investigate further
Projects
None yet
Development

No branches or pull requests