Infinite recursion - because module option with anything type and overlays


I am hitting infinite recursion in nixpkgs overlays when used in a particular way with my flake-parts module. I think there is no loop logically, so I hope this can be fixed with a refactor or some annotations.

Here is reproduction: github flake.

What happens there is I defined a flake-parts module, with pkgsConfig.overlays option and pkgsFor option. The pkgsConfig is what I set, setting it to single simple overlay:

pkgsConfig.overlays = [
    (final: _: {
        mybash = final.bash;

The pkgsFor option is not supposed to be set but used and I use it to define a default package:

packages.default = (config.pkgsFor system).hello;

But building the default package fails with:

       error: infinite recursion encountered

       at /nix/store/f4vqvc518zhqbc8nckx5fnqbh7n6v56z-source/flake.nix:20:24:

           19|             (final: _: {
           20|               mybash = final.bash;
             |                        ^
           21|             })


So important thing is that defining the pkgsFor instance without that pkgs flake-parts module, but in the same way - works and doesn’t loop. That is if I define the pkgsFor simply in let bindings corresponding to the module options and setting the values to the module default values - then the package builds.

Also, defining the pkgsFor with that flake-parts module, but setting pkgsConfig.overlays to just an empty list also doesn’t run into an recursion error.

What is going on?



So the problem is when merging overlays of type listOf anything, the single overlay gets treated as attribute set and the merge tries to find its fixpoint? Thats my guess, but either way, specifying:

      overlays = mkOption {
        description = "List of overlays.";
        default = [ ];
        type = types.raw; # important to avoid infinite recursion when merging option

fixes the infinite recursion!!