nixpkgs PR 136605 adds a feature to perform a dry-run to show which users/groups will be added or removed without switching to the configuration. The PR enables this feature for the system.activationScripts.users activation script by default which Agenix also uses.
This breaks nixos-rebuild because the agenixRoot attribute is not available during the dry-run. Disabling dryRun for the system.activationScripts.users script resolves the issue.
It looks like agenix can check if the NIXOS_ACTION environment variable equals "dry-activate" to alter behavior during a dry-run. I'm not sure what all is required to make the agenixRoot attribute available.
Here's the full stack trace:
error: attribute 'agenixRoot' missing
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:72:71:
71| else if done ? ${entry} then f done (tail todo)
72| else f (done // listToAttrs [{name = entry; value = 1;}]) ([predefined.${entry}] ++ tail todo);
| ^
73| in (f {} arg).result;
… while evaluating 'f'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:61:17:
60| let
61| f = done: todo:
| ^
62| if todo == [] then {result = []; inherit done;}
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:72:16:
71| else if done ? ${entry} then f done (tail todo)
72| else f (done // listToAttrs [{name = entry; value = 1;}]) ([predefined.${entry}] ++ tail todo);
| ^
73| in (f {} arg).result;
… while evaluating 'f'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:61:17:
60| let
61| f = done: todo:
| ^
62| if todo == [] then {result = []; inherit done;}
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:66:21:
65| if isAttrs entry then
66| let x = f done entry.deps;
| ^
67| y = f x.done (tail todo);
… while evaluating the attribute 'result'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:68:18:
67| y = f x.done (tail todo);
68| in { result = x.result ++ [entry.text] ++ y.result;
| ^
69| done = y.done;
… while evaluating 'textClosureList'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:59:33:
58|
59| textClosureList = predefined: arg:
| ^
60| let
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:76:35:
75| textClosureMap = f: predefined: names:
76| concatStringsSep "\n" (map f (textClosureList predefined names));
| ^
77|
… while evaluating 'textClosureMap'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/strings-with-deps.nix:75:35:
74|
75| textClosureMap = f: predefined: names:
| ^
76| concatStringsSep "\n" (map f (textClosureList predefined names));
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/nixos/modules/system/activation/activation-script.nix:40:9:
39|
40| ${textClosureMap id (withHeadlines) (attrNames withHeadlines)}
| ^
41|
… while evaluating 'systemActivationScript'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/nixos/modules/system/activation/activation-script.nix:20:33:
19|
20| systemActivationScript = set: onlyDry: let
| ^
21| set' = filterAttrs (_: v: onlyDry -> v.supportsDryActivation) (mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set);
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/nixos/modules/system/activation/activation-script.nix:135:17:
134| internal = true;
135| default = systemActivationScript (removeAttrs config.system.activationScripts [ "script" ]) true;
| ^
136| };
… while evaluating the attribute 'default'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/nixos/modules/system/activation/activation-script.nix:135:7:
134| internal = true;
135| default = systemActivationScript (removeAttrs config.system.activationScripts [ "script" ]) true;
| ^
136| };
… while evaluating the attribute 'value.content'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:708:14:
707| { _type = "override";
708| inherit priority content;
| ^
709| };
… while evaluating the attribute 'value._type'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:648:73:
647| highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
648| strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
| ^
649| in {
… while evaluating anonymous lambda
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:547:19:
546| # Avoid sorting if we don't have to.
547| if any (def: def.value._type or "" == "order") defs''.values
| ^
548| then sortProperties defs''.values
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:547:14:
546| # Avoid sorting if we don't have to.
547| if any (def: def.value._type or "" == "order") defs''.values
| ^
548| then sortProperties defs''.values
… while evaluating the attribute 'values'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:551:9:
550| in {
551| values = defs''';
| ^
552| inherit (defs'') highestPrio;
… while evaluating the attribute 'mergedValue'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:557:5:
556| # Type-check the remaining definitions, and merge them. Or throw if no definitions.
557| mergedValue =
| ^
558| if isDefined then
… while evaluating the option `system.dryActivationScript':
… while evaluating the attribute 'value'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:525:9:
524| in warnDeprecation opt //
525| { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
| ^
526| inherit (res.defsFinal') highestPrio;
… while evaluating anonymous lambda
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/modules.nix:140:72:
139| # For definitions that have an associated option
140| declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
| ^
141|
… from call site
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/attrsets.nix:304:20:
303| then recurse (path ++ [name]) value
304| else f (path ++ [name]) value;
| ^
305| in mapAttrs g set;
… while evaluating 'g'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/lib/attrsets.nix:301:19:
300| g =
301| name: value:
| ^
302| if isAttrs value && cond value
… from call site
… while evaluating the attribute 'system.dryActivationScript'
… while evaluating the attribute 'dryActivationScript' of the derivation 'nixos-system-infinitejest-21.11.20210908.09cd65b'
at /nix/store/6dcqil119qr3sad2lp9ykkkc852ppmqm-source/pkgs/stdenv/generic/make-derivation.nix:205:7:
204| // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) {
205| name =
| ^
206| let
nixpkgs PR 136605 adds a feature to perform a dry-run to show which users/groups will be added or removed without switching to the configuration. The PR enables this feature for the system.activationScripts.users activation script by default which Agenix also uses.
This breaks nixos-rebuild because the agenixRoot attribute is not available during the dry-run. Disabling dryRun for the system.activationScripts.users script resolves the issue.
system.activationScripts.users.supportsDryActivation = lib.mkForce false;
It looks like agenix can check if the NIXOS_ACTION environment variable equals "dry-activate" to alter behavior during a dry-run. I'm not sure what all is required to make the agenixRoot attribute available.
Here's the full stack trace: