I have added a (add-hook 'js2-mode-hook 'my-js2-mode-setup) the following hook to a use-package init section:

(use-package js2-mode
  :ensure t
  :interpreter (("node" . js2-mode))
  :mode "\\.\\(js\\|json\\)$"
  :bind (:map js2-mode-map
              ("C-c C-p" . js2-print-json-path))
  (add-hook 'js2-mode-hook 'my-js2-mode-setup)
  (add-hook 'js-mode-hook 'js2-minor-mode)
  (setq js2-highlight-level 3
        js2-mode-show-parse-errors nil
        js2-mode-show-strict-warnings nil))

I was not convinced the hook was running so I removed the my-js2-mode-set-up function and no error has occurred.

Why is this? Should I have the init section enclosed in a progn as there is more than one statement?

  • You don't need to progn if there is more than one statement. I replaced my-js2-mode-setup with a function defined in :preface and it works just fine.
    – fhdhsni
    Jun 11, 2017 at 10:53
  • what is preface?
    – dagda1
    Jun 11, 2017 at 10:53
  • It is evaluated before everything else. Usually used for defining functions. Like this (use-package js2-mode :preface (defun foo() (message "foo here")) ...
    – fhdhsni
    Jun 11, 2017 at 10:56
  • thanks, where would you use defadvice?
    – dagda1
    Jun 11, 2017 at 11:10
  • How is defadvice relevant to this question?
    – phils
    Jun 11, 2017 at 11:17

2 Answers 2


Use-package is designed NOT to stop on error. All errors are reported in the *Warnings* buffer. This way you can almost always start your emacs and fix any errors from within Emacs.

From use-package README https://github.com/jwiegley/use-package:

Additionally, if an error occurs while initializing or configuring a package, this will not stop your Emacs from loading. Rather, the error will be captured by use-package, and reported to a special *Warnings* popup buffer, so that you can debug the situation in an otherwise functional Emacs.


The add-hook forms need to go in the :config block instead of :init.

As the package is not yet required at the time of evaluating :init, the HOOK to which the add-hook is adding a function is not yet defined. Even so, trying to do add-hook will "work" as that new HOOK will be initialized with a nil value (From C-h f add-hook). BUT that also means that that HOOK will not get the initial value, if non-nil, as set in the package, as the package is not yet loaded.

Here's a little dummy example:

Let's say there is a foo.el:

;; my foo package -- foo.el
(defvar foo-hook (lambda () (message "hi")))
(provide 'foo)

.. and the user's init.el

;; my init.el
(use-package foo
  (add-hook 'foo-hook #'ignore))

So I would suggest to always do add-hook calls in :config. That way:

  • First the package gets loaded
  • Then that HOOK gets an initial value as set by the package (though, it is very rare for a hook to have a non-nil initial value)
  • Then the add-hook from the :config gets triggered.
  • add-hook works even if the package is not loaded yet. From the docstring: "If HOOK is void, it is first set to nil."
    – clemera
    Aug 11, 2017 at 21:03
  • @compunaut Thanks! You are correct. I now remember that certain packages do not care to formally define hooks with defvar or defcustom (which is bad) and initialize those with just add-hook. I still stand by the suggestion of adding hooks in :config for better config robustness. Aug 11, 2017 at 21:44

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.