30 May 2025 |
Skyler | In reply to @mattsturg:matrix.org
Without getting too much into the weeds, infinite recursion can show up for a number of reasons. Not just defining imports via a config value (such as non-special args).
For example, trying to use an arg that doesn't exist usually shows up as infinite recursion too. E.g. if you were defining or using args in mismatched module evals.
As for "merging in" special args; this isn't really possible because the whole point of special args is that they aren't defined by the module system.
Is there a reason you need different args per user instead of using home-manager's shared extraSpecialArgs NixOS option?
For example, trying to use an arg that doesn't exist usually shows up as infinite recursion too. E.g. if you were defining or using args in mismatched module evals.
Yeah, I've definitely seen this... the way I'm doing it at the moment is generating a list of modules for my NixOS config, including both modules that set home-manager user modules up and modules that set home-manager.users.${username}._module.args ... the symptoms are the same as if I don't set them though... I guess maybe they are in mismatched module evals (how would I know?)
As for "merging in" special args; this isn't really possible because the whole point of special args is that they aren't defined by the module system.
gotcha - yeah... the special args are defined in NixOS and I have what I want them to be for the homes in NixOS. If I could merge in a different type for each attr of the attrsOf I think I could do it, since as I could merge in another submodule that has the specialArgs I want ... unfortunately it's pretty much all or nothing there
Is there a reason you need different args per user instead of using home-manager's shared NixOS option?
it's a pretty artificial constraint, but I'm not making the structure for homes themselves - so I can't guarentee that there aren't conflicting home args set in different homes ... I'm trying to make a thing that can be used to take standalone home-manager homes and put them in nixos systems - and the individual standalone home-manager home spec I have here doesn't share special args... what I'm trying to do is mostly plumbing, I hadn't considered seeing if I could get the home spec modified to better fit this case (or just, you know, ban setting these to different things) | 23:06:28 |
Matt Sturgeon | I'd strongly consider discouraging specialArgs in general. There are other ways to pass args into modules without needing to add "special" args to the entire configuration (module eval).
I appreciate specialArgs can be convenient and are often used in examples and personal configs where portability isn't an issue, but it is much better to apply these "external" values directly into the individual modules that need them.
E.g. this module uses inputs.self via lexical scoping; no specialArgs needed:
{
outputs = inputs: {
nixosModules = {
default = {
# import all the other modules in this flake:
imports = builtins.attrValues (builtins.removeAttrs inputs.self.nixosModules [ "default" ]);
};
};
};
}
This one has access to inputs via an extra set of args applied before the module:
# flake.nix
{
outputs =
inputs:
let
inherit (inputs.nixpkgs) lib;
inherit (lib.modules) importApply;
in
{
nixosModules = {
someModuleWithInputs = importApply ./module.nix { inherit inputs; };
};
};
}
# module.nix
{ inputs }@appliedArgs:
{ lib, config, ... }@moduleArgs:
{
imports = [
inputs.foo.nixosModules.default
];
}
| 23:33:23 |
31 May 2025 |
Matt Sturgeon | Sorry if I was dismissive before, I'm fresh with coffee now! 😁
including both modules that set home-manager user modules up and modules that set home-manager.users.${username}._module.args ... the symptoms are the same as if I don't set them though... I guess maybe they are in mismatched module evals
Well, in that example the { _module.args } bit is a home-manager user module. So assuming you're defining it for the same user that has modules using the args, they should be present.
(how would I know?)
I would try a simple example; define two modules for the same user. One defining module args, the other trying to use them in some non-recursive way.
As for "merging in" special args; this isn't really possible because the whole point of special args is that they aren't defined by the module system.
I was over-simplifying when I said this; because the submodule with the special args you're setting is a separate module eval, you are still defining them outside that module eval. However IDK if the submodule type supports type-merging them. e.g. if you declared a duplicate option with additional special args in its submoduleWith type.
I.e. in some cases you can declare the same option twice, and the module system will merge those declarations (not definitions!). This is kinda black magic though, and only supports merging certain aspects of options. Most of the time you'll get an "option declared multiple times" error.
If you really do need this and none of the alternative approaches I suggested are sufficient, I would suggest sending a PR to home-manager which adds a "per-user" extraSpecialArgs option.
The existing extraSpecialArgs option is declared here, and used here.
Such an option might look like:
userSpecialArgs = lib.mkOption {
type = types.attrsOf types.attrs;
default = { };
example = lib.literalExpression "{ fred = { inherit freds-inputs; }; }";
description = ''
Per-user extra `specialArgs` passed to Home Manager, only for the specified users.
See also {option}`home-manager.extraSpecialArgs`.
'';
};
cc Austin Horstman
Feel free to ping me in any relevant PRs.
| 08:28:37 |
| bew joined the room. | 13:10:36 |
bew | Hello!
Given I am making a custom module system, and I have set _module.args.foobar = "something".
I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1).
In my case I cannot just hardcode another priority because the extendModules might be called multiple times, thus I need to override foobar multiple times.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here.
Am I missing something?
| 13:11:04 |
bew | * Hello!
Given I am making a custom module system, and I have set _module.args.foobar = "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode another priority because the extendModules might be called multiple times, thus I need to override foobar multiple times. I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here. Am I missing something?
| 13:13:31 |
bew | * Hello!
Given I am making a custom module system, and I have set _module.args.foobar = "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode another priority because the extendModules might be called multiple times, thus I need to override foobar multiple times. I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here. Am I missing something?
| 13:14:01 |
bew | * Hello!
Given I am making a custom module system, and I have set _module.args.foobar = "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode another priority because the extendModules might be called multiple times, thus I need to override foobar multiple times. Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here.
Am I missing something?
| 13:18:15 |
bew | * Hello!
I am making a custom module system, and I have set _module.args.foobar = mkOverride 1000 "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode 999 here because the extendModules might be called multiple times, thus I need to override foobar multiple times with priority 998 then 997, etc... Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here.
Am I missing something?
| 13:21:48 |
bew | * Hello!
I am making a custom module system, and I have set _module.args.foobar = mkOverride 1000 "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode 999 here because the extendModules might be called multiple times, thus I need to override foobar multiple times with priority 998 then 997, etc... Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here.
What am I missing? 🤔
| 13:22:48 |
bew | * Hello!
I am making a custom module system, and I have set _module.args.foobar = mkOverride 1000 "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode 999 here because the extendModules might be called multiple times, thus I need to override foobar multiple times with priority 998 then 997, etc... Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here. It kind of make sense to me because foobar is not an option, it's really part of the config at this point, but then is there still a way to access the priority?
What am I missing? 🤔
| 13:56:33 |
bew | * Hello!
I am making a custom module system, and I have set _module.args.foobar = mkOverride 1000 "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode 999 here because the extendModules might be called multiple times, thus I need to override foobar multiple times with priority 998 then 997, etc... Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here. It kind of make sense to me because foobar is not an option, it's really part of the config at this point, but then is there still a way to access the priority from eval ?
What am I missing? 🤔
| 14:00:34 |
bew | * Hello!
I am making a custom module system, and I have set _module.args.foobar = mkOverride 1000 "something" . I'm trying to use eval.extendModules and override the _module.args.foobar with a value with higher priority (by 1). In my case I cannot just hardcode 999 here because the extendModules might be called multiple times, thus I need to override foobar multiple times with priority 998 then 997, etc... Currently I do this by keeping track of the previous priority manually out of band (I re-implemented a kind of extendModules myself before discovering that it exists 👀), but I recently discovered highestPrio which would allow me to find the previous prio directly on the last module eval.
I tried finding the highestPrio field of _module.args.foobar using eval.options._module.args.foobar.highestPrio but it's saying that foobar doesn't exist here. It kind of make sense to me because foobar is not an option, it's really part of the config at this point, but then is there still a way to access the priority from module eval ?
What am I missing? 🤔
| 14:00:51 |
Matt Sturgeon | Options have highestPrio (and other) attributes, however in this case _module.args is the option, not _module.args.foobar .
foobar is an attribute of _module.args ' value .
You may find it helpful to inspect this in nix repl .
In this case you can use lib.modules.mergeAttrDefinitionsWithPrio to get the priorities of each attr of _module.args ; there's an example of this in the nixos/modules/misc/nixpkgs.nix module. | 19:03:54 |
1 Jun 2025 |
bew | I see, thanks a lot for the answer! In the end I went with a custom option to store some state about the current eval, which allows me to directly be able to access highestPrio on those options 👍 | 10:11:25 |
bew | * I see, thanks a lot for the answer! In the end I went with a custom options to store some state about the current eval, which allows me to directly be able to access highestPrio on those options 👍 | 10:11:35 |
Matt Sturgeon | Awesome. That sounds more idiomatic!
Just a general design titbit: extendModules is more efficient when you don't read anything from the extended configuration.
Due to laziness, extended module evals don't actually need to be fully evaluated, so if you only read from the "final" extended configuration, then you don't need to also spend time evaluating the other ones. | 10:18:21 |
bew | * I see, thanks a lot for the answer! In the end I'm going with a custom options to store some state about the current eval, which allows me to directly be able to access highestPrio on those options 👍 | 11:39:28 |
| Sean Thawe joined the room. | 23:48:32 |
2 Jun 2025 |
bew | Yes, I'm quite happy with what I managed to do ✨ Basically I made a system where I can easily eval an initial config, then call theconfig.lib.extendWith somemodule that returns a new config with the somemodule applied on top. This module can access the previous config if it needs it, and the extendWith can be done on any config 'instance' ❤️ https://github.com/bew/dotfiles/blob/main/nix/kit-system/tests.nix if you want to take a look
I use this in my dotfiles to make mini module systems to configure nvim/zsh/tmux, and incrementally enable various flags for different flake outputs..
| 00:33:01 |
bew | * Yes, I'm quite happy with what I managed to do ✨ Basically I made a system where I can easily eval an initial config, then call theconfig.lib.extendWith somemodule that returns a new config with the somemodule applied on top. This module can access the previous config if it needs it, and the extendWith can be done on any config 'instance' ❤️ https://github.com/bew/dotfiles/blob/main/nix/kit-system/tests.nix if you want to take a look
I use this in my dotfiles to make small independent module systems to configure nvim/zsh/tmux, and incrementally enable various flags for different flake outputs..
| 00:34:14 |
4 Jun 2025 |
| robsliwi changed their display name from Robert Sliwinski to robsliwi. | 18:30:25 |
6 Jun 2025 |
| @creepinson:matrix.org left the room. | 00:18:42 |
| sportshead joined the room. | 18:45:00 |
7 Jun 2025 |
| matrixrooms.info mod bot (does NOT read/send messages and/or invites; used for checking reported rooms) left the room. | 22:32:07 |
| matrixrooms.info mod bot (does NOT read/send messages and/or invites; used for checking reported rooms) joined the room. | 23:25:32 |
9 Jun 2025 |
| SigmaSquadron joined the room. | 13:06:30 |
| Philipp changed their display name from Spaenny to Philipp. | 20:46:30 |
16 Jun 2025 |
Brisingr05 | Redacted or Malformed Event | 07:00:33 |
| @ygt:matrix.org left the room. | 21:50:42 |