14

If an error is signalled in Emacs Lisp code, and debug-on-error is t, I get a backtrace buffer that makes it easy to figure out where the error occurred. However, for errors that occur while processing a response from the network asynchronously, it would be annoying to have the backtrace buffer pop up, so I'd rather catch the error with condition-case and log it.

So when I'm handling an error in condition-case, is there a way to get access to the backtrace at the point of the error? Calling the backtrace function gets the backtrace of the code inside the handler, which is not what I'm looking for.

(condition-case e
    (do-something-that-might-fail)
  (error
    (message "%s"
             ;; This gets the wrong backtrace!
             (with-temp-buffer
               (let ((standard-output (current-buffer)))
                 (backtrace)
                 (buffer-string))))))
3
  • 1
    My magithub-error function does something similar to this I think, but I'm not at a computer right now. It may help regardless. Commented Oct 28, 2016 at 12:06
  • 1
    That's a general problem with any language that manages its stack in a similar way. A way to handle that is to signal an error which already has stack information attached to it. I.e. in your case, you'd have do-something-that-might-fail generate stack-trace and attach it to the error it raises.
    – wvxvw
    Commented Oct 28, 2016 at 12:14
  • 1
    debbugs.gnu.org/cgi/bugreport.cgi?bug=24617#8 has a suggestion (haven't tried it myself)
    – npostavs
    Commented Oct 28, 2016 at 19:34

1 Answer 1

2

The easiest thing to do is to create your own debugger in the environment in which the error occurs. That goes something like this:

(defun my-debugger (&rest debugger-args)
  (message "BACKTRACE: %s"
           (with-temp-buffer
             (let ((standard-output (current-buffer)))
               (backtrace)
               (buffer-string)))))

(let ((debugger #'my-debugger))
  (foobar)) ; Runs a function with no definition!

The let environment uses this custom debugger function my-debugger for the duration of the code inside it, so if you encounter an un-handled error, the "debugger" will run, which essentially just prints out the message. This debugger runs in the environment where the error occurred, so your backtrace will tell you what happened.

Note: This code has two (solvable) problems that I'll leave for you. First, you probably want to strip off first few stack frames, as they pertain to the invocation of backtrace. Second, you will get a message also indicating the error (for example, in the case above, "let: Symbol's function definition is void: foobar"). Neither are huge problems, but I didn't want to muddy my response.

2
  • 1
    NOTE: as-is this will only get the first backtrace until there is user input. It is necessary to reset internal-when-entered-debugger at the end of the debugger function for multiple consecutive backtrace retrievals to succeed. See the discussion here for the motivation.
    – Chris Hunt
    Commented Dec 2, 2020 at 3:37
  • 1
    Can probably use (backtrace-to-string (backtrace-get-frames 'backtrace)) directly to avoid the temp buffer.
    – erjoalgo
    Commented Jun 28, 2023 at 5:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.