summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2020-08-14 19:26:18 +0200
committerMaximilian Bosch <maximilian@mbosch.me>2020-08-18 15:25:26 +0200
commitfa30c9abed61f30218a211842204705986d486f9 (patch)
treea0a0792636239c0aebecadad80b9c50e30f34d1b /lib
parentfe7bab33d75cece4750fd1a51406a6e8993807ce (diff)
downloadnixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar.gz
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar.bz2
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar.lz
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar.xz
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.tar.zst
nixpkgs-fa30c9abed61f30218a211842204705986d486f9.zip
lib/modules: improve error-message for undeclared options if prefix contains no options
An easy-to-make mistake when declaring e.g. a submodule is the accidental
confusion of `options` and `config`:

    types.submodule {
      config = {
        foo = mkOption { /* ... */ };
      };
    }

However the error-message

  The option `[definition 1-entry 1].foo' defined in `<expr.nix>' does not exist.

is fairly unhelpful because it seems as the options are declared at the
first sight. In fact, it took a colleague and me a while to track down such
a mistake a few days ago and we both agreed that this should be somehow caught
to save the time we spent debugging the module in question.

At first I decided to catch this error in the `submodules`-type directly
by checking whether `options` is undeclared, however this becomes fairly
complicated as soon as a submodule-declaration e.g. depends on existing
`config`-values which would've lead to some ugly `builtins.tryExec`-heuristic.

This patch now simply checks if the option's prefix has any options
defined if a point in evaluation is reached where it's clear that the
option in question doesn't exist. This means that this patch doesn't
change the logic of the module system, it only provides a more detailed
error in certain cases:

  The option `[definition 1-entry 1].foo' defined in `<expr.nix>' does not exist.

  However it seems as there are no options defined in [definition 1-entry 1]. Are you sure you've
  declared your options properly? This happens if you e.g. declared your options in `types.submodule'
  under `config' rather than `options'.
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix15
1 files changed, 13 insertions, 2 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 9c308d347cf..2ec34699809 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -115,8 +115,19 @@ rec {
 
       checkUnmatched =
         if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
-          let firstDef = head merged.unmatchedDefns;
-          in throw "The option `${showOption (prefix ++ firstDef.prefix)}' defined in `${firstDef.file}' does not exist."
+          let
+            firstDef = head merged.unmatchedDefns;
+            baseMsg = "The option `${showOption (prefix ++ firstDef.prefix)}' defined in `${firstDef.file}' does not exist.";
+          in
+            if attrNames options == [ "_module" ]
+              then throw ''
+                ${baseMsg}
+
+                However there are no options defined in `${showOption prefix}'. Are you sure you've
+                declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
+                under `config' rather than `options'.
+              ''
+            else throw baseMsg
         else null;
 
       result = builtins.seq checkUnmatched {