| name | nix-debug |
| description | Deep debugging of Nix expressions, evaluation, and derivations |
| allowed-tools | ["Bash","Read"] |
Nix Deep Debugging
nix eval - Complete Reference
nix eval .#attr
nix eval .#attr --json
nix eval .#attr --raw
nix eval .#attr --apply 'x: x.meta'
nix eval .#attr --apply 'builtins.attrNames'
nix eval --expr '1 + 1'
nix eval --expr 'builtins.attrNames (import ./. {})'
nix eval --expr --impure 'builtins.getEnv "HOME"'
nix eval nixpkgs#hello.meta
nix eval github:NixOS/nixpkgs#lib.version
nix eval .#attr --show-trace
nix eval .#attr --debugger
nix eval .#attr -vvvvv
nix repl - Interactive Debugging
nix repl --expr 'builtins.getFlake (toString ./.)'
nix repl .#
nix repl '<nixpkgs>'
nix repl --expr 'import <nixpkgs> {}'
REPL Commands
:? Help
:p EXPR Pretty print (shows structure)
:t EXPR Show type
:b DRV Build derivation
:l PATH Load nix file
:lf FLAKE Load flake
:r Reload all files
:q Quit
:doc FUNC Show documentation (Nix 2.10+)
REPL Introspection Patterns
# List all attributes
builtins.attrNames someSet
# Recursive attribute listing
lib.attrsets.mapAttrsRecursive (path: value: path) someSet
# Check what's in a module
builtins.attrNames config.services
# Find where option is defined
options.services.nginx.enable.definitionsWithLocations
# Function signature
builtins.functionArgs someFunction
# Returns: { arg1 = false; arg2 = true; }
# true = has default value
# Get source location
builtins.unsafeGetAttrPos "enable" options.services.nginx
# Returns: { file = "/path"; line = 42; column = 5; }
Built-in Debug Functions
builtins.trace
# Print message, return value unchanged
builtins.trace "checkpoint reached" someValue
# Print with value
builtins.trace "value is: ${toString x}" x
# Conditional trace
builtins.trace (if debug then "debug: ${msg}" else "") value
lib.debug Functions
# Print and return value
lib.debug.traceVal expr
# Prints: trace: <value>
# Returns: <value>
# Deep evaluate then print
lib.debug.traceValSeq expr
# Print first, return second
lib.debug.traceSeq exprToPrint exprToReturn
# Trace with label
lib.debug.traceValFn (x: "myVar = ${toString x}") myVar
# Trace attribute set keys
lib.debug.traceSeqN 2 someSet result # depth 2
Debugging Assertions
# Show what failed
assert lib.assertMsg (x > 0) "x must be positive, got: ${toString x}";
result
# Warn without failing
lib.warn "deprecated option used" value
lib.warnIf condition "message" value
Interactive Debugger (Nix 2.9+)
nix eval .#attr --debugger
Debugger Commands
:bt Show backtrace
:env Show current environment
:st Step into
:s Step over
:c Continue
:q Quit debugger
Trigger Debugger Programmatically
builtins.break value # Breaks here when --debugger is used
nix-instantiate - Deep Evaluation
nix-instantiate --eval --strict -E 'import ./.'
nix-instantiate --parse ./file.nix
nix-instantiate ./default.nix
nix-instantiate --eval -A attrPath ./file.nix
Derivation Debugging
nix derivation show .#package
nix log .#package
nix log /nix/store/<hash>-name
nix why-depends .#package .#dependency
nix path-info -rsSh .#package
nix path-info --json .#package | jq
Error Diagnosis Cookbook
"infinite recursion encountered"
nix eval .#attr --show-trace 2>&1 | tail -100
"attribute 'x' missing"
nix eval .#someSet --apply builtins.attrNames
:p builtins.attrNames someSet
nix eval --expr 'someSet ? x'
"called with unexpected argument 'x'"
nix eval --expr 'builtins.functionArgs someFn'
"cannot coerce X to string"
# Problem: ${nonString}
# Solutions:
toString value # for numbers, paths
builtins.toJSON value # for complex values
lib.generators.toPretty {} value # pretty print
"is not a function"
nix eval --expr 'builtins.typeOf problemValue'
Module System Debugging
nix eval .#nixosConfigurations.host.config.services.nginx.enable
nix eval .#nixosConfigurations.host.options.services.nginx.enable.files
nix eval .#nixosConfigurations.host.options.services.nginx.enable.definitionsWithLocations --json | jq
nix eval --expr '.#nixosConfigurations.host.options.services ? nginx'
Performance Debugging
time nix eval .#attr --json >/dev/null 2>&1
NIX_SHOW_STATS=1 nix eval .#attr
nix eval --expr '
builtins.trace "before import" (
let x = import ./.;
in builtins.trace "after import" x
)
'
Quick Debug Snippets
# Print current file/line
builtins.trace "at ${__curPos.file}:${toString __curPos.line}" value
# Dump entire set structure
builtins.trace (builtins.toJSON (builtins.mapAttrs (k: v: builtins.typeOf v) someSet)) result
# Assert with helpful message
assert builtins.isAttrs x || throw "Expected set, got ${builtins.typeOf x}";