NixOS & Configuration

Module evaluation enters an infinite recursion

Nix cannot resolve a configuration dependency cycle. Inspect config-dependent imports, self-referencing values and argument timing before restructuring modules.

On this page
  1. Symptoms & scope
  2. Possible causes
  3. Diagnose safely
  4. Evidence-guided next steps
  5. References & review
  6. Related problems

Symptoms & scope

  • Evaluation reports infinite recursion encountered.
  • The trace repeatedly returns to imports or the same option dependency.

Relevant environment

NixOS module fixed-point evaluation, custom modules and flake specialArgs.

Recognizable messages (synthetic examples)
error: infinite recursion encountered

The surrounding trace is required; this message also occurs outside NixOS modules.

Possible causes

These are possible explanations, not a confirmed diagnosis. Several independent faults can coexist.

  • imports cannot depend on a config value whose definition itself requires collecting those imports.
  • Self-referencing option expressions or mutually derived module arguments can also create cycles.

Diagnose safely

Run one command at a time in the relevant session. Read the explanation first. Uppercase placeholders need your own values; tools and privileges vary by distribution. These commands are displayed here and never executed by the website.

Check 1

Read the real module checkout; focus on locations named by the saved evaluation trace.

rg -n 'imports|config\.|_module\.args|specialArgs' /etc/nixos

Interpret the result: Config use in ordinary values can be valid, but using it to choose imports can cycle before values exist. specialArgs is available earlier.

Check 2

Replace the file with the module named by the error; parsing reads it without evaluating or building it.

nix-instantiate --parse /etc/nixos/configuration.nix

Interpret the result: Successful parsing confirms only grammar. It does not resolve imports or prove the dependency graph is acyclic.

Evidence-guided next steps

Make import selection independent of config

If imports consult config, import the available modules statically and put conditional option definitions behind lib.mkIf. For external import parameters, pass deliberately static values via specialArgs.

Precautions: mkIf does not make a config-dependent imports list safe. Avoid passing the entire config back through specialArgs.

Recovery / rollback: Restore the previous module structure from version control if the refactor changes unintended option defaults.

Did this solution help you?

Share this solution#

Break the proven value dependency cycle

If the trace identifies two values derived from each other, introduce one independent input and derive the others from it. Replace self-references such as assigning an option from its own final value with a local let binding or separate input option.

Precautions: Change only the identified cycle. Removing unrelated imports can silence an error by silently disabling functionality.

Recovery / rollback: Restore original bindings and inputs; evaluate or build the candidate without activation before keeping the refactor.

Did this solution help you?

Share this solution#

References & review

This guide was prepared from primary project or distribution sources and reviewed on the date shown. This is an editorial source check, not evidence that a fix was reproduced on your hardware. Diagnostic log examples are synthetic fixtures. Version-dependent details must be checked against your installed release.