`error: infinite recursion encountered` when trying to make a `vars.nix` to set and read variables for systems

I’m trying to build a configuration where there is a vars.nix file in the configuration root like this:

.
├── vars.nix
├── flake.nix
├── flake.lock
├── modules/
│   ├── audio.nix
│   ├── nvidia.nix
│   ├── hyprland.nix
│   ├── clipboard.nix
│   └── ....nix
└── hosts/
    └── nixosbtw/
        ├── users/
        │   └── alex-home.nix
        ├── configuration.nix
        ├── disko.nix
        └── hardware-configuration.nix

vars.nix looks like this:

{ lib, config, ... }: {
  options.vars = {
    mainUser = lib.mkOption {
      description = "Name of the main user of the system";
      default = "alex";
    };

    # hostname = lib.mkOption {
    #   description = "The hostname for the system";
    #   default = "default-hostname";
    # };

    # timeZone = lib.mkOption {
    #   description = "The time zone for the system";
    #   default = "UTC";
    # };
  };

  config.vars = {
    # Provide access to the resolved values
    mainUser = config.vars.mainUser;
    # hostname = config.vars.hostname;
    # timeZone = config.vars.timeZone;
  };
}

Parts of my configuration.nix for the nixosbtw host where i set and read (use) the variables:


{ pkgs, inputs, config, ... }:
{
  imports = [
    ./hardware-configuration.nix 
    inputs.home-manager.nixosModules.default

    ../../modules/lib.nix
    ../../vars.nix

    ./disko.nix
  ];

  vars.mainUser = "alex";

  hyprland.wlr_no_hardware_cursors = true;  
  hyprland.enable = true;

  # TODO set up breeze grub theme
  nix.settings.experimental-features = [ "nix-command" "flakes" ];

  boot.loader = {
    efi.canTouchEfiVariables = true;
    grub = {
      enable = true;
      devices = [ "nodev" ];
      efiSupport = true;
      useOSProber = true;
      extraConfig = ''
        set timeout=50
      '';
    };
  };
  
  home-manager = {
    extraSpecialArgs = { inherit inputs; };
    users = {
      "${config.vars.mainUser}" = import ./users/${config.vars.mainUser}-home.nix;
    };
  };

  networking.hostName = "nixosbtw";

  time.timeZone = "Europe/Vienna";
  time.hardwareClockInLocalTime = true;

  i18n.defaultLocale = "en_US.UTF-8";

  console = {
    font = "Lat2-Terminus16";
    keyMap = "de";
  };

  users.users.${config.vars.mainUser} = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
    uid = 12306;
    hashedPassword = "$argon2id$v=19$m=16,t=2,p=1$OE96V29oZHFSQXFXWGlFcw$ygLPc/hufJqvJMNhq+I3zw";
  };

  users.mutableUsers = false;

  services.openssh = {
    enable = true;
    settings = {
      AllowUsers = [ "${config.vars.mainUser}" ];
      PermitRootLogin = "no";
      KbdInteractiveAuthentication = false;
    };
    # ports = [ 22 ];
  };

  services.fail2ban = {
    enable = true;
    ignoreIP = [ "127.0.0.1" "::1" "192.168.0.111" ];
  };

  networking.firewall.enable = true;
  networking.firewall.allowedTCPPorts = [ 22 ];
  # networking.firewall.allowedUDPPorts = [ ... ];

  # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
  # and migrated your data accordingly. 
  system.stateVersion = "24.05";
}


This gives me a recursion error when installing on a remote machine using nixos-anywhere:

### Building the system closure ###
error:
       … while calling the 'head' builtin
         at /nix/store/7hw19rbs6p20l2gxbf13la04pcs2znmz-source/lib/attrsets.nix:1574:11:
         1573|         || pred here (elemAt values 1) (head values) then
         1574|           head values
             |           ^
         1575|         else

       … while evaluating the attribute 'value'
         at /nix/store/7hw19rbs6p20l2gxbf13la04pcs2znmz-source/lib/modules.nix:846:9:
          845|     in warnDeprecation opt //
          846|       { value = addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          847|         inherit (res.defsFinal') highestPrio;

       … while evaluating the option `system.build.toplevel':

       … while evaluating definitions from `/nix/store/7hw19rbs6p20l2gxbf13la04pcs2znmz-source/nixos/modules/system/activation/top-level.nix':

       … while evaluating the option `assertions':

       … while evaluating definitions from `/nix/store/alm3nymx19kvkc8my31niws5d81b9pri-source/nixos/common.nix':

       … while evaluating the option `home-manager.users':

       … while evaluating definitions from `/nix/store/55i70pmlzhplls2bnljvb0rnirsdq052-source/hosts/nixosbtw/configuration.nix':

       … while evaluating the option `vars.mainUser':

       … while evaluating definitions from `/nix/store/55i70pmlzhplls2bnljvb0rnirsdq052-source/vars.nix':

       (stack trace truncated; use '--show-trace' to show the full, detailed trace)

       error: infinite recursion encountered
       at /nix/store/7hw19rbs6p20l2gxbf13la04pcs2znmz-source/lib/modules.nix:846:9:
          845|     in warnDeprecation opt //
          846|       { value = addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          847|         inherit (res.defsFinal') highestPrio;

I may be taking a completely wrong approach here, as I am very new to NixOS. I appreciate any help!

That’s because you are setting config.vars.mainUser = config.vars.mainUser in your vars.nix.

You dont need to provide access to the resolved values either. They are already accessible when defined in options. I do a similar thing for my config by passing vars to specialArgs in my flake.nix with my user details (e.g. userDetails), and then importing that arg into my module.

So I would suggest refactoring by incorporating vars.nix into your flake.nix. I get what you are trying to do, but it makes a lot more sense to incorporate those options into the specific modules that use that option unless you want to use specialArgs. Then, you can set the values for that option in something like a default.nix file.

Here is my configuration if you want to reference it: nixos (I use the special args in this file)