Common errors & how to deal with them

All Emacs users eventually encounter an error, and those errors can be cryptic for the uninitiated. It pays to know how to interpret and deal with them.

The official Emacs manual lists a large number of them, but some of their explanations are not so great.

This guide goes over the most common ones a Doom user is likely to see.

:pushpin: Producing a backtrace from an error is always a good first step. A backtrace can tell you much more about an error (and where it came from). We will usually ask you to provide one in bug reports anyway.

void-function: XYZ

What it means

The function XYZ does not exist, but it was called anyway.

Why did it happen?

  • There is a typo in the function call.
  • Or XYZ existed at one point, but no longer does (or was renamed) and the caller hasn’t been updated.
  • Or XYZ exists, but is called before it is available. Perhaps the caller has made an incorrect assumption about when XYZ is and isn’t available.

How to deal with it

How you deal with this error depends on its origin. Generating a backtrace will tell you where that is. Once you know what function is responsible, use M-x find-function RET [function-name] to find its definition and inspect its code.

  • If the function is defined or called by a third-party package, the issue should be reported to them. Use M-x straight-visit-package-website to quickly open that package’s homepage in your browser.

  • If the function or caller is in your private config (in ~/.doom.d), then you must address it yourself. Perhaps you forgot to autoload the function or load its package before using it. For example:

    ;; declare to Emacs where to find XYZ when it is needed:
    (autoload 'XYZ "package-name")
    ;; or do the same with `use-package' instead:
    (use-package package-name
      :commands XYZ)
    ;; or just load it immediately
    (require 'package-name)
    
    ;; After any of the above you are free to use the function:
    (XYZ)
    
  • If the function is in Doom core or a Doom module, then report it to us. It may be a bug!

void-variable: XYZ

What it means

The variable XYZ does not exist, but it was used.

Why did it happen?

  • There is a typo in the variable name.
  • Or XYZ existed at one point, but no longer does (or was renamed) and the user hasn’t been updated.
  • Or XYZ exists, but is being used before it is loaded. Perhaps the caller has made an incorrect assumption about when XYZ is and isn’t available.

How to deal with it

How you deal with this error depends on where it originates. Generating a backtrace will tell you what function last referenced this variable. It’s a good idea to inspect that function with M-x find-function RET [function-name] and see how the XYZ variable is being used.

  • If the caller is in a third-party package, the issue should be reported upstream. Use M-x straight-visit-package-website to quickly launch that package’s homepage in your browser.

  • If the caller is in your private config (in ~/.doom.d), then you must address it yourself. Perhaps you forgot to set the variable, or load the package that defines it before using it. For example:

    ;; Setting the variable with setq will create it if it does not exist yet.
    ;; If it does exist, it will be changed.
    (setq XYZ 50)
    ;; You can use defvar instead, which won't change its existing value, if
    ;; XYZ is already defined, and also lets you define documentation for it.
    (defvar XYZ 50 "Defines how many cacodemons `use-XYZ' should invoke.")
    ;; Otherwise, load the variable's package eagerly, right before you use 
    ;; it. For example:
    (defun use-XYZ ()
      "The function that triggered the error in the backtrace."
      (require 'XYZ-package)
      (do-things-with XYZ))
    ;; or load it right away so you never have to worry about load order.
    (require 'XYZ-package)
    
    ;; then you are free to reference the variable however you like. e.g.
    (add-to-list 'XYZ 1)
    (push 2 XYZ)
    (setq XYZ (append XYZ (list 3 4 5)))
    
  • If the function that triggered the error is in Doom core or a Doom module, then report it to us, it may be a bug!

commandp: XYZ

What it means

XYZ is not a known “command” or does not exist. A command is a function that has been marked as an “interactive” function. If the function exists, this error indicates it hasn’t been marked as interactive, but is being used interactively (most commonly: as a keybind).

Why did it happen?

In Emacs parlance, a command is a function that has a (interactive) form at the top of its body. When a function is interactive, it can be called interactively using M-x or a keybind. This error occurs if a non-interactive (or non-existent) function is called interactively.

It can be reproduced like so:

(defun not-a-command ()
 (message "Do stuff"))

(defun is-a-command ()
  (interactive)
  (message "Do stuff"))

(map! "M-x" #'is-a-command)  ; works fine!

(map! "M-x" #'not-a-command) ; throws a commandp: not-a-command error
(defun not-a-command ()
 (message "Do stuff"))

(defun is-a-command ()
  (interactive)
  (message "Do stuff"))

(global-set-key (kbd "M-x") #'is-a-command)  ; works fine!

(global-set-key (kbd "M-x") #'not-a-command) ; throws a commandp: not-a-command error

How to deal with it

The function needs to be marked as interactive. Here are two ways to do so:

You defined the function yourself

Add (interactive) to the top of the function in question (following the docstring).

 (defun this-function-is-interactive ()
   "A docstring"
+  (interactive)
   ...)

This interactive form is powerful and can help you automatically feed arguments to a function when it is invoked through a keybind or M-x. More information about this can be found in the Emacs manual.

The function comes from a package

If you didn’t write the function yourself and the function isn’t interactive, then you must wrap it in a function that is:

This throws a commandp: not-a-command error when you press M-x:

(defun not-a-command ()
 (message "Stuff"))
(map! "M-x" #'not-a-command)

So either wrap it in an interactive function…

(defun interactive-not-a-command ()
  (interactive)
  (not-a-command))
(map! "M-x" #'interactive-not-a-command)  ; no problem!

…or do so inline with Doom’s cmd! helper macro:

(map! "M-x" (cmd! (not-a-command)))       ; no problem!

This throws a commandp: not-a-command error when you press M-x:

(defun not-a-command ()
 (message "Stuff"))
(global-set-key (kbd "M-x") #'not-a-command)

So either wrap it in an interactive function…

(defun interactive-not-a-command ()
  (interactive)
  (not-a-command))
(global-set-key (kbd "M-x") #'interactive-not-a-command)  ; no problem!

…or do so inline:

(global-set-key (kbd "M-x") (lambda () (interactive) (not-a-command)))

Key sequence … starts with non-prefix key …

What it means

Let’s say that a keybind exists on M-x, and that it’s bound to the command execute-extended-command. This means M-x is not a prefix key.

But what happens then, if you try to bind a command to the key sequence: M-x/. You get an error: Key sequence M-x / starts with non-prefix key M-x

TL;DR Emacs doesn’t like it when you treat non-prefix keys like they are prefix keys.

You can produce the error yourself with:

(map! "M-x" #'command-a)

(map! "M-x /" #'command-b) ; error!
(global-set-key (kbd "M-x") #'command-a)

(global-set-key (kbd "M-x /") #'command-b) 

Why did it happen?

This is a keybind conflict. You can determine where it originates from with a backtrace.

How to deal with it

You must resolve the conflict. For example:

  • Unbind the non-prefix key first:

    (map! "M-x" nil
          "M-x /" #'command-b)
    
  • Override the non-prefix key by binding your new key to a different keymap with higher precedence:

    (map! "M-x" #'execute-extended-command)
    (map! :map override "M-x /" #'command-b)
    

    This makes the original M-x keybind unavailable when this keymap is active. To get around that…

  • Bind a “conditional” key on a different keymap with higher precedence (which is only in effect when that condition is met):

    (map! "M-x" #'execute-extended-command)
    (map! :map override "M-x /" (cmds! CONDITION #'command-b))
    

    If CONDITION returns non-nil (when the key is pressed), command-b is invoked. Otherwise, Emacs falls back to execute-extended-command.

  • Or have the general.el library resolve keybinds for you by adding (general-auto-unbind-keys) to your config. Keep in mind, however, this prevents these errors on keys bound after this has been called, not before.

    There are theoretical performance implications in using this method, and I’m uncertain about any additional side-effects – it needs more testing!

:pushpin: See “How to (re)bind keys” for details on key bindings.

unable to find theme file for XYZ

What it means

Emacs could not find the definition file for the XYZ theme.

Why did it happen?

There are two ways to load themes in Emacs:

  • You load it explicitly by calling (load-theme 'THEME-NAME t)
  • You ask Doom to load it for you later: (setq doom-theme 'THEME-NAME) – which calls load-theme later in the startup process.

Emacs will search custom-theme-load-path (a global variable) for a file named THEME-NAME-theme.el (note the -theme.el suffix; forgetting it is a common cause for these errors).

:warning: Doom will search custom-theme-directory first. This is the opposite of how Vanilla Emacs behaves, which will search it last. Its value is ~/.doom.d/themes/ in Doom and ~/.emacs.d/ in vanilla.

This error occurs because XYZ-theme.el could not be found in any of the directories in custom-theme-load-path.

How to deal with it

  • Make sure there are no typos in the name of the theme.
  • Make sure that you refer to the theme as THEME-NAME (minus the -theme suffix), otherwise, Emacs would search for glorious-theme-theme.el, which likely isn’t what was intended.
  • If you wrote your own theme, make sure it is in one of the directories in custom-theme-load-path or custom-theme-directory (i.e. in ~/.doom.d/themes/ – if it doesn’t already exist, you must create it).
  • If the theme is loaded from a package, make sure the package is correctly installed.

If none of the above works, then try reporting it. Please be sure to include the name of the theme, how you are loading the theme (code), and the value of custom-theme-load-path and custom-theme-directory.

Cannot open load file: No such file or directory, …

What it means

Emacs tried to find an executable, a file, or Emacs package, but could not find it.

Why did it happen?

Emacs will throw this error up if:

  • An Emacs package was requested (e.g. (require 'NAME-OF-PACKAGE)), but no NAME-OF-PACKAGE.el could be found in your load-path.
  • Or a system executable was called (e.g. (call-process "git")), but no git executable was found in the exec-path variable (which should mirror the contents of your PATH environment variable).

:pushpin: The values of exec-path and load-path can be inspected using C-hv, followed by the name of the variable to inspect.

How to deal with it

To address this issue, you must first determine whether the missing resource is an executable or an Emacs package. Doing so is not always straight forward:

  • The biggest clue can be found in the error message. It will contain the name of the resource that Emacs failed to find. If you’re lucky, you’ll be able to recognize it, e.g. sqlite or git are obviously executables (unless someone writes an Emacs package with the same name one day, and you happen to be using it. Fortunately, this isn’t the case for these two at the time of writing).
  • If the type can’t be determined by the resource’s name, more detective work is needed.
    • If it’s an Emacs package:
      • You may find it in M-x find-library.
      • It may have -el or .el at the end of its name, or emacs- at the beginning. This is a common naming convention of Emacs packages.
    • If it’s an executable:
      • Executing which NAME in your shell (replace NAME with the name of the resource) should output a path to the executable (if it’s in your PATH).
      • If it’s the name of an LSP server program, it may have lsp or language-server in its name. This is no guarantee however, as some Emacs packages use this convention too, but it is more common that a user forgot to install an LSP server than an Emacs package.
  • If all else fails, it’s time for a backtrace! Use it to find the function where the error originates, then use M-x find-function to investigate it.

Once you finally know what type of resource it is:

If all else fails, let us know about it!

Error in private config: …

What it means

An error occurred while trying to load your private configuration (in ~/.doom.d).

Why did it happen?

This error often indicates a mistake in your private configuration, and may represent any of the errors above, only that they originate from your private config.

The cause of your error depends on what the rest of the error message says. For example:

Error in private config: config.el, (void-function xyz)

Means the non-existent function XYZ was called while Doom was loading ~/.doom.d/config.el, so the problem likely exists inside that file.

How to deal with it

To deal with this error, you need to know what caused it. Unless the error message implicates one of the errors covered by this guide, there are too many possibilities to cover here.

That said, the error message should include the file where the error originated (e.g. config.el, init.el, or packages.el), which gives you some place to start looking. Remember, a backtrace will usually help locate it! Failing that, try bisecting your config.

end-of-file ...

Will sometimes appear as “End of file during parsing”

What it means

The Emacs Lisp interpreter unexpectedly reached the end of an elisp file.

Why did it happen

The most common cause is an unclosed parenthesis, bracket, or quotation in your elisp somewhere.

How to deal with it

Open the problem file and do M-x check-parens to locate the issue (will find unbalanced parentheses, brackets, and quotations).

Honourable mentions

There are a slew of other common errors I think are self-explanatory, but are worth mentioning:

  • wrong-type-argument X Y — a type error; Y is the invalid data that was received and X is the predicate function that would return true if Y were a valid data type. The name of this predicate should clue you in to what data type was expected. e.g. wrong-type-argument number-or-marker-p nil means something expected a number or marker, but got nil instead.
  • wrong-number-of-arguments — a function was passed the wrong number of arguments.
2 Likes