"Infinite recursion encountered" by making module configurable

I’ve been changing my NixOS config to parameterize my config modules using options declarations. This has been working fine, except for my XServer config. The below is a minimal version of the offending module:

{ config, pkgs, lib, ... }:

with lib;
{
  options.os.xorg = {
    enable = pkgs.lib.mkOption {
      default = false;
      type = types.bool;
    };
  };

  config = mkIf config.os.xorg.enable {
    services.xserver = {
      enable = true;

      displayManager.lightdm = {
        enable = true;
        greeters.enso = {
          enable = true;
          blur = true;
        };
      };

      displayManager.defaultSession = "xsession";
      displayManager.session = [
        {
          manage = "desktop";
          name = "xsession";
          start = ''exec $HOME/.xsession'';
        }
      ];
    };
  };
}

When I include that module from my NixOS config, and set os.xorg.enable = true; from another module, I get the following error when I sudo nixos-rebuild test --flake '.':

error: infinite recursion encountered

       at /nix/store/kmy3yfc596gvfm5lkxzbq37kxizdj78r-source/lib/types.nix:461:58:

          460|         # Push down position info.
          461|         (map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs);
             |                                                          ^
          462|       emptyValue = { value = {}; };

--show-trace does not seem to produce any useful results; I can attach those if wanted.

If I comment out enable = true and the LightDM config block, it seems to move forwards. Similarly, if I comment out the options block, the config = mkIf ... line, and the corresponding ending curly brace, it works fine.

Expected outcome

I’d expect to be able to parameterize this module, like I’ve done with others.

Other information

  • NixOS 22.05
  • Nix v2.8.1
1 Like

I’ve tried narrowing down my flake output to literally just my xserver config and my machine’s settings with no other software; no dice.

I’ve also tried disabling nonfree software as per this older, probably unrelated Github issue: Infinite recursion when using allowUnfree · Issue #24251 · NixOS/nixpkgs · GitHub – that still doesn’t help (unsurprisingly).

The machine in question is an AMD A10-7850K; it seems to be using the radeon driver for graphics. I haven’t tried it on other machines yet; that’s next I suppose.

Here’s what I get when I run sudo nixos-rebuild test --flake '.' --show-trace: NixOS infinite recursion error - Pastebin.com It’s too large to paste into Discourse it seems.

Any help, including “here’s some references on how to read that stacktrace” or “here’s a better way to debug your Nix modules” are welcome :stuck_out_tongue:

I can’t really test my theory, though config = mkIf is always dangerous, therefore:

--- parts/foo.nix       2022-11-27 10:37:02.863466398 +0100
+++ parts/foo.nix2      2022-11-27 10:37:45.428234978 +0100
@@ -4,8 +4,7 @@
     };
   };
 
-  config = mkIf config.os.xorg.enable {
-    services.xserver = {
+  config.services.xserver = mkIf config.os.xorg.enable {
       enable = true;
 
       displayManager.lightdm = {
2 Likes

Interesting, I didn’t know config = mkIf was dangerous; it’s threaded throughout my config, haha.

I’ll have to give it a try later and report back, thanks!

Unfortunately, I’m still getting the same error. My module now looks like

{ config, pkgs, lib, ... }:

with lib;
{
  options.os.xorg = {
    enable = pkgs.lib.mkOption {
      default = false;
      type = types.bool;
    };
  };

  config.services.xserver = mkIf config.os.xorg.enable {
    // elided everything inside mkIf
  };
}

Playing around a bit more, I find if I comment out the two lines pointed out below, the module gets past the error message. I’ve always killed the process at that point – not interested in leaving my system without X or a graphical login screen…

  config.services.xserver = mkIf config.os.xorg.enable {
    #enable = true; # <-- commented this line

    displayManager.lightdm = {
      #enable = true; # <-- and this line
      greeters.enso = {
        enable = true;
        blur = true;
      };
    };
  };

I’m still seeing this issue under NixOS 22.11.

I made a minimal replication of the issue, which I’ve uploaded here:

All I need to replicate the problem is to check this out somewhere and run

nixos-rebuild build --flake '.#infrectest'

to see the problem.

Any thoughts are welcome – I’m still not counting out that I’ve missed something/done something wrong/have a bad mental model!

(Edit: Changed command to do nixos-rebuild build instead of nixos-rebuild switch, which is correctly pointed out as dangerous on an arbitrary machine – thanks NobbZ)

1 Like
diff --git a/modules/nixos/desktop/default.nix b/modules/nixos/desktop/default.nix
index 2f0ff42..bd302e3 100644
--- a/modules/nixos/desktop/default.nix
+++ b/modules/nixos/desktop/default.nix
@@ -3,7 +3,7 @@
 with lib;
 {
   options.os.xorg = {
-    enable = pkgs.lib.mkOption {
+    enable = lib.mkOption {
       default = false;
       type = types.bool;
     };

This fails with a message about having no root file system and boot manager configured, so it’s probably fine.

PS: never ask people to run nixos-rebuild switch but nixos-rebuild build instead!

Thanks, I think that did it!

Good catch on the build vs . switch.

Thank you, I had a similar issue and this fixed it for me. I had no idea config = mkIf is an anti-pattern, and the official docs even explicitly use it in the Example section: NixOS modules - NixOS Wiki

Should it be noted there? And do you know why it causes problems?

Wait what? No, config = mkIf definitely is not an antipattern. It should work basically 100% of the time. It’s used all the time in nixpkgs/nixos/modules.

1 Like