Eventually, you will encounter a cryptic error while using Emacs, but more information can be extracted from errors if you produce a backtrace from it. This should be your first step when dealing with any error you don’t immediately recognize — you will always be asked for one in bug reports, and they may help you locate and resolve the issue yourself.
See “How to debug issues” for a more general guide on dealing with problems in Emacs.
What is a backtrace?
A backtrace lays out the series of function calls that led to the error, and what arguments they were called with. This can tell you much more about where in Doom’s, Emacs’, or a package’s code base an error originated from.
How to make sense of a backtrace
For the sake of demonstration, here is the backtrace of an error I artificially created by typing M-x eval-expression
RET (+ 1 nil)
:
Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
+(1 nil)
eval-expression((+ 1 nil) nil nil 127)
funcall-interactively(eval-expression (+ 1 nil) nil nil 127)
command-execute(eval-expression record)
execute-extended-command(nil "eval-expression" "eval-expression")
funcall-interactively(execute-extended-command nil "eval-expression" "eval-expression")
command-execute(execute-extended-command)
Let me break this down:
-
The first line will always be in the format:
Debugger entered--Lisp error: (ERROR_TYPE [EXTRA_DATA...])
ERROR_TYPE is the name of the error. Emacs lists its internal errors in its manual, and another Discourse post lists a few examples of common errors and how to interpret them. The exact format of
EXTRA_DATA
varies from error to error, however.In any case, here is what you can glean from this particular error,
(wrong-type-argument number-or-marker-p nil)
:-
wrong-type-argument
indicates a data type error. This means something in the expression(+ 1 nil)
was expecting data of one type, but received data in another, illegal type, and cannot proceed. -
The first argument of a
wrong-type-argument
error is the name of a predicate function that the data failed to satisfy. In this case,number-or-marker-p
. This suggests a number (or marker, but I won’t go into that here) was expected, and the actual data given was neither. -
The
nil
is the illegal data that was received instead of a number or marker.
-
-
The next line of the backtrace is
+(1 nil)
, and it will always be the block of code emitted the error.To spoil the mystery,
+
expects all its arguments to be numeric, so passing it a non-number will cause this type error.C-hf
+
will reveal the+
function’s documentation, which says:Return sum of any number of arguments, which are numbers or markers.
-
The rest of the backtrace tells you the series of function calls that led to this point. For this contrived example they aren’t important, but more complex errors may require you work further backwards to find the true cause.
In those cases, I suggest you read “Inspecting source code” for ways to directly inspect functions in the backtrace.
How to produce a backtrace
Simply, you set the debug-on-error
variable to a non-nil
value. Here are three ways to do so:
-
Start Emacs with
emacs --debug-init
. Use this for errors that occur at startup -
Doom Emacs users should activate
doom-debug-mode
:- Evil users: SPChdd
- Users that have disabled evil: C-hdd.
- Otherwise: M-x
doom-debug-mode
-
If the above don’t work, or you don’t use Doom, use M-x
toggle-debug-on-error
, instead.
Once debug-on-error
is activated, go ahead and reproduce an error, and a new window will appear to display a backtrace.
Unfortunately, not all errors produce a backtrace. For example: when the error is emitted by the modeline or a
post-command-hook
function, Emacs suppresses them. This is done to protect against really destructive errors breaking Emacs’ UI.When this happens let us know in your bug report, but try to include the full error message that appears in the *Messages* buffer. It may, at least, mention where the error was suppressed.
From bin/doom
If the error you encountered was emitted from bin/doom
, a limited backtrace
will already be displayed, but the full backtrace is written to ~/.emacs.d/.local/doom.error.log
. Attach this file to your bug report.
From frozen Emacs
If Emacs freezes or hangs, you can produce a backtrace to determine what logic Emacs is hanging on with one of the following:
-
Send a
USR2
signal to the Emacs process:pkill -USR2 emacs
orkill -USR2 $EMACSPID
.EMACSPID
should be replaced with the process id of your frozen instance of Emacs. Use the commandspgrep emacs
orps aux | grep emacs
to help you locate its PID. -
Turn on
debug-on-quit
, mash C-g, and hope for the best.
Not all freezes can be recovered from, unfortunately. If the above doesn’t work, your only option is to forcibly kill the Emacs process.