Here is an example. I am evaluating this using nix repl and a simple flake
{ lib, config, ... }:
let
consumeFunction =
{
dependedOn,
myOptionalOption ? "${dependedOn} here",
}:
myOptionalOption;
in
{
options = with lib; {
myCustomList = mkOption {
type = types.listOf (
types.submodule {
options = {
dependedOn = mkOption {
type = types.str;
description = "The other option depends on this";
};
myOptionalOption = mkOption {
type = types.str;
description = "I want to leave this empty when I make the option";
};
};
}
);
};
myCheck = mkOption { type = types.str; };
};
config = {
myCustomList = [
{ dependedOn = "1"; }
{ dependedOn = "2"; }
];
myCheck = lib.concatStrings (map consumeFunction config.myCustomList);
};
}
Evaluating myCheck results in
nix-repl> outputs.nixosConfigurations.test.config.myCheck
error:
… while evaluating the attribute 'value'
at /nix/store/12azrzlywd7jmsg1q9n4dpqqgb33p2wl-source/lib/modules.nix:1118:7:
1117| // {
1118| value = addErrorContext "while evaluating the option `${showOption loc}':" value;
| ^
1119| inherit (res.defsFinal') highestPrio;
… while evaluating the option `myCheck':
… while evaluating the attribute 'mergedValue'
at /nix/store/12azrzlywd7jmsg1q9n4dpqqgb33p2wl-source/lib/modules.nix:1192:5:
1191| # Type-check the remaining definitions, and merge them. Or throw if no definitions.
1192| mergedValue =
| ^
1193| if isDefined then
… while evaluating definitions from `/nix/store/46ak6xqnq7spyv5849l1jhaid0y6sbvm-source/test.nix':
… while evaluating the option `myCustomList."[definition 1-entry 1]".myOptionalOption':
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
error: The option `myCustomList."[definition 1-entry 1]".myOptionalOption' was accessed but has no value defined. Try setting the option.
However if I do this
{ lib, config, ... }:
let
consumeFunction =
{
dependedOn,
myOptionalOption ? "${dependedOn} here",
}:
myOptionalOption;
in
{
options = with lib; {
myCustomList = mkOption {
type = types.listOf (types.attrsOf types.anything);
};
myCheck = mkOption { type = types.str; };
};
config = {
myCustomList = [
{ dependedOn = "1"; }
{ dependedOn = "2"; }
];
myCheck = lib.concatStrings (map consumeFunction config.myCustomList);
};
}
And evaluate it again
nix-repl> :r
Loading flake '.'...
Added 9 variables.
_type, inputs, lastModified, lastModifiedDate, narHash, nixosConfigurations, outPath, outputs, sourceInfo
nix-repl> outputs.nixosConfigurations.test.config.myCheck
"1 here2 here"
In both configs I did not set myOptionalOption, yet the second example can successfully evaluate by using the ? operator. Why does the first example not work?
I am not setting the default value where I define the option because you can see it depends on another attribute in the same attribute set.