I asked already in matrix, but probably here it will be easier to reference for the future. I’m getting an infinite recursion. Here’s the code. Just copy the flake.nix
to an empty folder and run nix flake check --show-trace
; you’ll get the error:
{
outputs = {
self,
nixpkgs,
}: rec {
# A module that defines some args for other modules
nixosModules.args = {
# This arg lets you see that there's no infinite recursion here
_module.args.disk = "/dev/sda";
# This arg is a hosts inventory; infinite recursion happens here
_module.args.inventory = rec {
all = {
host1 = {
provider_name = "a";
deployment_version = "v1";
};
};
get = hostName: all.${hostName};
};
};
# Another module that uses the prvious one's inputs
nixosModules.fileSystem = {
disk,
inventory,
...
}: let
host = inventory.get "host1";
pinnedConfigs.a.v1 = {
# Old deployments didn't use custom partitions
fileSystems."/" = {
device = disk;
fsType = "ext4";
};
};
in
# If you uncomment this line and comment the next one, the infinite recursion disappears
# pinnedConfigs.a.v1;
pinnedConfigs.${host.provider_name}.${host.deployment_version}
// {
# However, this one is using `disk`, which won't fail with recursion, but it comes from the same place
boot.loader.grub.device = disk;
};
# The host configuration
nixosConfigurations.host1 = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = with nixosModules; [
args
fileSystem
{networking.hostName = "host1";}
];
};
};
}
flake.lock
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1677080879,
"narHash": "sha256-0SjW4/d3Rkw6C7hHZ5lxT4r6Pw9vzQb6Il6zYWwe2Bo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f5dad40450d272a1ea2413f4a67ac08760649e89",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
Error logs
error: infinite recursion encountered
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:483:28:
482| builtins.addErrorContext (context name)
483| (args.${name} or config._module.args.${name})
| ^
484| ) (lib.functionArgs f);
… while evaluating the module argument `inventory' in ":anon-1395:anon-1":
… while calling anonymous lambda
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:481:44:
480| context = name: ''while evaluating the module argument `${name}' in "${key}":'';
481| extraArgs = builtins.mapAttrs (name: _:
| ^
482| builtins.addErrorContext (context name)
… from call site
… while calling 'fileSystem'
at /nix/store/xixw4qsdq4ay1ggg7shkpa4mi5pmam50-source/flake.nix:23:31:
22| # Another module that uses the prvious one's inputs
23| nixosModules.fileSystem = {
| ^
24| disk,
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:490:8:
489| # works.
490| in f (args // extraArgs)
| ^
491| else
… while calling 'applyModuleArgsIfFunction'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:466:39:
465|
466| applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
| ^
467| let
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:361:55:
360| if isFunction m || isAttrs m then
361| unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
| ^
362| else if isList m then
… while calling 'unifyModuleSyntax'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:434:34:
433| of ‘options’, ‘config’ and ‘imports’ attributes. */
434| unifyModuleSyntax = file: key: m:
| ^
435| let
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:361:11:
360| if isFunction m || isAttrs m then
361| unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
| ^
362| else if isList m then
… while calling 'loadModule'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:359:53:
358| # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
359| loadModule = args: fallbackFile: fallbackKey: m:
| ^
360| if isFunction m || isAttrs m then
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:400:22:
399| let
400| module = loadModule args parentFile "${parentKey}:anon-${toString n}" x;
| ^
401| collectedImports = collectStructuredModules module._file module.key module.imports args;
… while evaluating the attribute 'disabled'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:395:13:
394| collectResults = modules: {
395| disabled = concatLists (catAttrs "disabled" modules);
| ^
396| inherit modules;
… while calling anonymous lambda
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:419:31:
418| disabledKeys = map moduleKey disabled;
419| keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
| ^
420| in map (attrs: attrs.module) (builtins.genericClosure {
… from call site
… while calling 'filterModules'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:413:36:
412| # modules recursively. It returns the final list of unique-by-key modules
413| filterModules = modulesPath: { disabled, modules }:
| ^
414| let
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:426:7:
425| in modulesPath: initialModules: args:
426| filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
| ^
427|
… while calling anonymous lambda
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:425:37:
424|
425| in modulesPath: initialModules: args:
| ^
426| filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:258:25:
257| merged =
258| let collected = collectModules
| ^
259| (specialArgs.modulesPath or "")
… while calling 'reverseList'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/lists.nix:406:17:
405| */
406| reverseList = xs:
| ^
407| let l = length xs; in genList (n: elemAt xs (l - n - 1)) l;
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:262:33:
261| ({ inherit lib options config specialArgs; } // specialArgs);
262| in mergeModules prefix (reverseList collected);
| ^
263|
… while calling 'byName'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:542:25:
541| */
542| byName = attr: f: modules:
| ^
543| zipAttrsWith (n: concatLists)
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:559:21:
558| # an attrset 'name' => list of submodules that declare ‘name’.
559| declsByName = byName "options" (module: option:
| ^
560| [{ inherit (module) _file; options = option; }]
… while evaluating the attribute 'matchedOptions'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:637:14:
636| in {
637| inherit matchedOptions;
| ^
638|
… while calling 'mapAttrsRecursiveCond'
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/attrsets.nix:530:5:
529| # Attribute set to recursively map over.
530| set:
| ^
531| let
… from call site
at /nix/store/4nxnb4jsbk18vxvzmmy109zlj9kmw5x1-source/lib/modules.nix:270:28:
269| # For definitions that have an associated option
270| declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
| ^
271|
… while checking the NixOS configuration 'nixosConfigurations.host1'
at /nix/store/xixw4qsdq4ay1ggg7shkpa4mi5pmam50-source/flake.nix:46:5:
45| # The host configuration
46| nixosConfigurations.host1 = nixpkgs.lib.nixosSystem {
| ^
47| system = "x86_64-linux";
… while checking flake output 'nixosConfigurations'
at /nix/store/xixw4qsdq4ay1ggg7shkpa4mi5pmam50-source/flake.nix:46:5:
45| # The host configuration
46| nixosConfigurations.host1 = nixpkgs.lib.nixosSystem {
| ^
47| system = "x86_64-linux";
Questions:
- Why is this producing an infinite recursion?
- How to fix it?