summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2021-03-11 11:57:38 +0100
committerMaximilian Bosch <maximilian@mbosch.me>2021-03-11 14:55:56 +0100
commite878fc4aac3a9cecf5f6509fd887824c52a20af3 (patch)
tree789ee0cfe25b17bc952aacfab91ee068d804fd56 /lib
parent2dbf082e8d1c32aa63135ebe7ed2d084a13aea1c (diff)
downloadnixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar.gz
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar.bz2
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar.lz
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar.xz
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.tar.zst
nixpkgs-e878fc4aac3a9cecf5f6509fd887824c52a20af3.zip
lib/modules: better error message if an attr-set of options is expected
I recently wrote some Nix code where I wrongly set a value to an option
which wasn't an actual option, but an attr-set of options. The mistake I
made can be demonstrated with an expression like this:

    {
      foo = { lib, pkgs, config, ... }: with lib; {
        options.foo.bar.baz = mkOption {
          type = types.str;
        };
        config.foo.bar = 23;
      };
    }

While it wasn't too hard to find the cause of the mistake for me, it was
necessary to have some practice in reading stack traces from the module
system since the eval-error I got was not very helpful:

    error: --- TypeError --------------------------------------------------------- nix-build
    at: (323:25) in file: /nix/store/3nm31brdz95pj8gch5gms6xwqh0xx55c-source/lib/modules.nix

       322|         foldl' (acc: module:
       323|                 acc // (mapAttrs (n: v:
          |                         ^
       324|                                    (acc.${n} or []) ++ f module v

    value is an integer while a set was expected
    (use '--show-trace' to show detailed location information)

I figured that such an error can be fairly confusing for someone who's
new to NixOS, so I decided to catch this case in th `byName` function in
`lib/modules.nix` by checking if the value to map through is an actual
attr-set. If not, a different error will be thrown.
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix11
-rwxr-xr-xlib/tests/modules.sh2
2 files changed, 12 insertions, 1 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 33a0d84a6d7..d3f10944e70 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -361,6 +361,17 @@ rec {
       */
       byName = attr: f: modules:
         foldl' (acc: module:
+              if !(builtins.isAttrs module.${attr}) then
+                throw ''
+                  You're trying to declare a value of type `${builtins.typeOf module.${attr}}'
+                  rather than an attribute-set for the option
+                  `${builtins.concatStringsSep "." prefix}'!
+
+                  This usually happens if `${builtins.concatStringsSep "." prefix}' has option
+                  definitions inside that are not matched. Please check how to properly define
+                  this option by e.g. referring to `man 5 configuration.nix'!
+                ''
+              else
                 acc // (mapAttrs (n: v:
                                    (acc.${n} or []) ++ f module v
                                  ) module.${attr}
diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh
index f843d303e44..2eddeec07b1 100755
--- a/lib/tests/modules.sh
+++ b/lib/tests/modules.sh
@@ -169,7 +169,7 @@ checkConfigOutput "foo" config.submodule.foo ./declare-submoduleWith-special.nix
 ## shorthandOnlyDefines config behaves as expected
 checkConfigOutput "true" config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-shorthand.nix
 checkConfigError 'is not of type `boolean' config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-noshorthand.nix
-checkConfigError 'value is a boolean while a set was expected' config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-shorthand.nix
+checkConfigError "You're trying to declare a value of type \`bool'\nrather than an attribute-set for the option" config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-shorthand.nix
 checkConfigOutput "true" config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-noshorthand.nix
 
 ## submoduleWith should merge all modules in one swoop