If you are new to Emacs, you may run into some errors, especially after you absorb elisp snippets from the Internet or elsewhere.
Don't panic. It happens. To ease your pain, in this post I will introduce some Emacs built-in features to help you solve the problems yourself.
Start Emacs Without Any Configurations
When you have some problems/errors with built-in features, the first thing you should do is to run emacs -Q
to start another Emacs instance without any configurations from your emacs.d
.
Here is how to do it in detail if you are not familiar with the terminal:
-
If you use Linux/macOS, open a terminal, then type the command
emacs -Q
.If you prefer to use Emacs in a terminal or run Emacs on a server, you can append an argument
-nw
to the command, that is,emacs -Q -nw
.P.S. If you want to know more about the command line arguments, you can look it up in the
man
manual (typeman emacs
in the shell) or typeemacs --help
to see the help information, so as to get a better understanding of how to run Emacs from the command line. -
Or if you use Windows, you can run the
cmd
program first (typeSuper+r cmd ENTER
),cd
into the Emacs bin directory, then typerunemacs.exe -Q
to run it.
Investigate the Faulty Package Within a Clean Emacs
emacs -Q
helps to debug built-in features. But when it comes to debugging third-party packages, like the ones you install from melpa, we need to do a bit more, as we need to load the package.
There are roughly two ways to load it.
Using the package
machinery
For example, if we now have a problem with my ppcompile package, we can prepare a snippet (e.g. in /tmp/try-ppcompile.el
) to prepare the debugging environment:
;; you don't need this if you never change this variable
(setq package-user-dir "~/.emacs.local.d/elpa")
;; init the package manager
(require 'package)
(package-initialize)
;; load the problematic package
(require 'ppcompile)
Now open up a terminal/cmd, type emacs -Q -l /tmp/try-ppcompile.el
, and it will start a fairly clean Emacs with ppcompile loaded. From there, we can investigate further to see the problem.
Directly load from a specific directory
There are times that you can't utilize the package machinery to load the package, for example, you git-clone a package and load it from your local file system directly. In that case, you can use Emacs' -L
argument to specify the directory.
For example, type emacs -Q -L /tmp/ppcompile/ --eval "(require 'ppcompile)"
to launch a new Emacs with the package and start debugging immediately.
Note that you can specify more than one directory.
Use --debug-init
To Debug Start-up Errors
It's not uncommon that when you update your emacs.d
, emacs errors when you run it next time.
Don't panic! Look carefully, and you will see that Emacs already tells you how to troubleshoot it. (Pay attention to the second red line on the above screenshot)
Open a terminal, type emacs --debug-init
, as Emacs tells us in the message, to start a new one. It will tell you where the error exactly comes from and the backtrace. Be patient and try to understand the problem, you will come up with a solution, hopefully! (The root cause in the screenshot is that the a-bug-function
function is not defined)
M-x toggle-debug-on-error
to Enable Debugging
(In case you do not know yet, here is how to type M-x toggle-debug-on-error
on the keyboard: ALT+x toggle-debug-on-error RETURN
)
You may see something like the below when you're using Emacs:
To simulate such an error, for example, say we have a silly welcome
command as below:
(defun welcome ()
(interactive)
(this-func-not-exist))
Now when you type M-x welcome
to invoke the command, you will see the error as in the above screenshot.
Now, type M-x toggle-debug-on-error
to enable debugging, then it will bring up a new window with the backtrace when we M-x welcome
once again.
From the backtrace, we can see that the error is because the function of this-func-not-exist
does not exist, so the welcome
command fails.
Set the debug-on-message
Variable
Other times, you may see some unexpected message on the echo area at the bottom. You can try to play around the debug-on-message
variable to get the backtrace of where it comes from and figure it out.
For example, the below command will send out a message welcome who?
when you invoke it:
(defun welcome ()
(interactive)
(message "welcome who?"))
Let's pretend that we now want to find out who print the nonsense message of welcome who
, and we can utilize the debug-on-message
variable to set up a regular expression, for instance, (setq debug-on-message "welcome who")
.
Once there is a message that matches the regexp, Emacs will trap it into the debugger, and we will see who prints that message:
Other Debugging Helpers and Facilities
Variable ways to look up help docs:
C-h f
to look up a function(C-h f
means to typeCTRL+h f
in the keyboard)C-h v
to look up a variableC-h k
to look up a keybindingC-h m
to look up which major mode and minor modes are enabled in the current bufferC-h l
to view lossage, put it in another way, you will see the history of the invoked commands in a dedicated buffer
Misc:
M-x describe-char
to see the properties of the character at point, for example, its font face.debug-on-entry
function Emacs starts the debugger automatically when your function has an error, also refer to debug-on-entry (Programming in Emacs Lisp) - www.gnu.org.debug-on-quit
variable refer to debug-on-quit (Programming in Emacs Lisp) - www.gnu.org--init-directory
Emacs 29 adds a command line argument of--init-directory
to specify a directory other than~/.emacs.d/
to run Emacs, where we can put our debugging code to do the investigation separately.