Skip to content

Commit fa30c9a

Browse files
committed
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'.
1 parent fe7bab3 commit fa30c9a

1 file changed

Lines changed: 13 additions & 2 deletions

File tree

lib/modules.nix

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,19 @@ rec {
115115

116116
checkUnmatched =
117117
if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
118-
let firstDef = head merged.unmatchedDefns;
119-
in throw "The option `${showOption (prefix ++ firstDef.prefix)}' defined in `${firstDef.file}' does not exist."
118+
let
119+
firstDef = head merged.unmatchedDefns;
120+
baseMsg = "The option `${showOption (prefix ++ firstDef.prefix)}' defined in `${firstDef.file}' does not exist.";
121+
in
122+
if attrNames options == [ "_module" ]
123+
then throw ''
124+
${baseMsg}
125+
126+
However there are no options defined in `${showOption prefix}'. Are you sure you've
127+
declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
128+
under `config' rather than `options'.
129+
''
130+
else throw baseMsg
120131
else null;
121132

122133
result = builtins.seq checkUnmatched {

0 commit comments

Comments
 (0)