main

Advanced Nix Workflows

This reference consolidates advanced Nix workflows that are used less frequently but remain valuable for specific situations.

Core workflows (used frequently) are in separate workflow files:

  • Build (workflows/Build.md)
  • Develop (workflows/Develop.md)
  • Flakes (workflows/Flakes.md)
  • Package (workflows/Package.md)
  • Secrets (workflows/Secrets.md)
  • Deploy (workflows/Deploy.md)

Debug - Debugging Nix Expressions and Builds

Debug Nix expressions, evaluation errors, and build failures.

When to Use

  • “debug nix expression”
  • “nix evaluation error”
  • “troubleshoot nix build”
  • “nix error messages”

Quick Commands

Evaluation Debugging

# Show evaluation trace
nix eval .#package --show-trace

# Evaluate with verbosity
nix eval .#package -vvv

# Show derivation
nix show-derivation .#package

# Inspect attribute path
nix eval .#nixosConfigurations.hostname.config.services

Build Debugging

# Build with full logs
nix build .#package -L
nix build .#package --print-build-logs

# Keep failed build directory
nix build .#package --keep-failed

# Show trace on error
nix build .#package --show-trace

# Maximum verbosity
nix build .#package -vvv --show-trace -L

Interactive Debugging

# Enter build environment
nix develop .#package

# Enter failed build directory
cd /tmp/nix-build-*

# Run phases manually
unpackPhase
patchPhase
configurePhase
buildPhase

Understanding Error Messages

Infinite Recursion

error: infinite recursion encountered

Cause: Circular dependency or self-referencing attribute

Debug:

# Problem
{
  x = y;
  y = x;  # Infinite recursion!
}

# Fix: Break the cycle
{
  x = lib.mkDefault value;
  y = config.x;
}

Attribute Not Found

error: attribute 'foo' missing

Debug:

# Check what attributes exist
nix eval .#nixosConfigurations.hostname --apply builtins.attrNames

# Check nested attributes
nix eval .#nixosConfigurations.hostname.config --apply "x: builtins.attrNames x.services"

# Use --show-trace to see where error originates
nix eval .#package --show-trace

Type Errors

error: value is a set while a string was expected

Debug:

# Check type of value
nix eval .#value --apply builtins.typeOf

# Print value for inspection
nix eval .#value --apply "x: builtins.trace x x"

# Show detailed type error
nix eval .#value --show-trace

Hash Mismatches

error: hash mismatch in fixed-output derivation
  got:    sha256-AAAA...
  wanted: sha256-BBBB...

Fix:

# Copy the "got" hash to your expression
# Or use nix-prefetch for correct hash
nix-prefetch-url https://example.com/file.tar.gz
nix-prefetch-github owner repo --rev commit-hash

Debugging Techniques

Trace Values

# Simple trace
value = builtins.trace "Debug: ${toString someValue}" someValue;

# Trace with lib
value = lib.traceVal someValue;
value = lib.traceValSeq "message" someValue;

# Trace attribute names
value = lib.traceSeq (builtins.attrNames attrs) attrs;

# Deep trace
value = lib.traceValSeqN 3 someNestedValue;

Evaluate Expressions

# Evaluate simple expression
nix eval --expr '1 + 1'

# Evaluate with nixpkgs
nix eval --expr 'with import <nixpkgs> {}; lib.version'

# Evaluate flake attribute
nix eval .#nixosConfigurations.hostname.config.networking.hostName

# Evaluate and show as JSON
nix eval .#package --json

# Evaluate and show as XML
nix eval .#package --xml

Check Configuration

# Check NixOS configuration validity
nixos-rebuild build --flake .#hostname --dry-run

# Show configuration options
nix eval .#nixosConfigurations.hostname.options

# Check if option exists
nix eval .#nixosConfigurations.hostname.options.services.nginx.enable.defined

# Show option documentation
nixos-option services.nginx.enable

Debugging Build Failures

Inspect Build Environment

# Enter build environment
nix develop .#package

# Check environment variables
env | grep -i nix
printenv

# Check build tools available
which gcc make cmake

# Check paths
echo $PATH
echo $PKG_CONFIG_PATH

Manual Build Steps

# Enter development shell
nix develop .#package

# Run phases manually
unpackPhase
ls -la

cd $sourceRoot
patchPhase

configurePhase
# Fix any configuration issues

buildPhase
# Fix build errors

checkPhase
installPhase

Inspect Failed Build

# Build with --keep-failed
nix build .#package --keep-failed

# Failed build kept at:
cd /tmp/nix-build-package-*.drv-0/

# Examine source
ls -la
find . -type f -name "*.log"

# Check build log
cat build.log

# Re-run failed command manually
./configure
make

Debug Build Script

# Show builder script
nix show-derivation .#package | jq '.[].env.builder'

# Show full derivation
nix derivation show .#package

# Print build environment
nix develop .#package --command printenv

Debugging Evaluation Errors

Stack Traces

# Show full stack trace
nix eval .#package --show-trace

# Example output:
# error: undefined variable 'foo'
#
#        at /path/to/file.nix:42:5:
#           41|   bar = {
#           42|     baz = foo;
#              |           ^
#           43|   };

Find Definition Location

# Find where option is defined
nix eval .#nixosConfigurations.hostname.options.services.nginx.enable.definitionsWithLocations

# Find where value is set
nix eval .#nixosConfigurations.hostname.options.services.nginx.enable.files

Check Module Evaluation

# Evaluate specific module
nix eval -f ./module.nix

# Check module with config
nix eval --expr 'import ./module.nix { lib = import <nixpkgs/lib>; }'

# Show module errors
nix-instantiate --eval --strict ./module.nix

Debugging Package Builds

Check Dependencies

# Show build dependencies
nix-store -q --references $(nix-build -A package)

# Show runtime dependencies
nix-store -q --requisites $(nix-build -A package)

# Show dependency tree
nix-store -q --tree $(nix-build -A package)

# Why is package kept?
nix-store --query --roots $(nix-build -A package)

Missing Dependencies

# Check what's needed
ldd result/bin/program

# Patch with nix
nix develop -c ldd ./program

# Auto-patch with autoPatchelfHook
nativeBuildInputs = [ autoPatchelfHook ];

Wrong Version Built

# Check what will be built
nix-build '<nixpkgs>' -A package --dry-run

# Check version in store
nix-store -q --hash $(nix-build -A package)

# Force specific version
nix build nixpkgs/nixos-23.11#package

Debugging NixOS Configurations

Configuration Evaluation

# Build configuration
nixos-rebuild build --flake .#hostname --show-trace

# Dry build to see what changes
nixos-rebuild dry-build --flake .#hostname

# Evaluate specific option
nix eval .#nixosConfigurations.hostname.config.system.stateVersion

Module Conflicts

error: The option `services.foo.enable' is defined multiple times

Debug:

# Find all definitions
nix eval .#nixosConfigurations.hostname.options.services.foo.enable.definitionsWithLocations

# Check module imports
nix eval .#nixosConfigurations.hostname.options._module.args --apply "x: builtins.attrNames x"

Service Failures

# Check service status after deployment
systemctl status servicename

# Check service logs
journalctl -u servicename -n 50

# Check generated config
systemctl cat servicename

# Verify config file
cat /etc/systemd/system/servicename.service

Debugging Flakes

Flake Evaluation

# Check flake
nix flake check

# Show flake outputs
nix flake show

# Evaluate flake metadata
nix flake metadata

# Lock file issues
nix flake lock --update-input nixpkgs

Input Problems

# Check inputs
nix flake metadata | grep -A 10 Inputs

# Update specific input
nix flake update nixpkgs

# Show input derivation
nix flake metadata --json | jq .locks

Pure Evaluation Errors

error: access to absolute path '/home/...' is forbidden in pure eval mode

Fix:

# Don't use absolute paths
# Bad
path = /home/user/file.nix;

# Good
path = ./file.nix;

# Or use --impure flag (not recommended)
nix build --impure

Advanced Debugging

Debug with nix repl

# Start repl
nix repl

# Load flake
:lf .

# Explore outputs
outputs.packages.x86_64-linux

# Load nixpkgs
:l <nixpkgs>

# Test expressions
lib.version
pkgs.hello

# Tab completion works
outputs.nixosConf[TAB]

Profile Evaluation

# Time evaluation
time nix eval .#package

# Show evaluation statistics
nix eval .#package --show-stats

# Profile build
nix build .#package --profile /tmp/profile

Debug with breakpoints

# In your expression
value = builtins.break (someExpression);

# Build will pause, entering debugger
# Commands:
# :continue - Continue evaluation
# :quit - Abort evaluation
# :env - Show environment
# :value - Show current value

Common Debug Patterns

# Debug helper
debug = msg: val: builtins.trace msg val;

# Usage
result = debug "Processing ${name}" (processValue value);

Conditional Debugging

# Only debug when flag is set
let
  debugFlag = false;
  debug = msg: val:
    if debugFlag
    then builtins.trace msg val
    else val;
in
  debug "Value" someValue

Assert Debugging

# Use assertions to catch errors early
{ ... }:

assert someCondition; {
  # Your config
}

# Better with message
{ lib, ... }:

lib.assertMsg someCondition "Error: condition not met"

Debugging Tools

nix-tree

# Install
nix-shell -p nix-tree

# Explore dependencies interactively
nix-tree $(nix-build -A package)

nix-diff

# Compare two derivations
nix-diff $(nix-build -A package1) $(nix-build -A package2)

nix-du

# Analyze disk usage
nix-du -s=500MB

# Show largest paths
nix-du | head -20

Debugging Best Practices

  1. Use –show-trace: Always show full stack traces
  2. Keep failed builds: Use --keep-failed to inspect
  3. Enable verbose logs: Use -L flag for build logs
  4. Use nix repl: Interactive exploration is powerful
  5. Check documentation: Many options have examples
  6. Test in isolation: Build packages separately
  7. Use nix develop: Debug in build environment
  8. Check flake.lock: Ensure inputs are correct

Emergency Debugging

System Won’t Boot

# Boot to previous generation (at boot menu)
# Or from rescue system:

# Mount nixos
mount /dev/sdX /mnt
mount /dev/sdY /mnt/boot

# Chroot
nixos-enter

# List generations
nix-env --list-generations --profile /nix/var/nix/profiles/system

# Rollback
/nix/var/nix/profiles/system-42-link/bin/switch-to-configuration switch

Out of Disk Space

# Clean old generations
nix-collect-garbage -d

# Delete specific generation
nix-env --delete-generations 10 11 12

# Optimize store
nix-store --optimize

# Find large paths
du -sh /nix/store/* | sort -h | tail -20

Resources


Security - Security Best Practices

Harden NixOS systems with security best practices and configurations.

When to Use

  • “harden nixos”
  • “nixos security”
  • “security hardening”
  • “apparmor nixos”

Quick Commands

Enable Hardened Profile

# Import hardened profile
imports = [
  <nixpkgs/nixos/modules/profiles/hardened.nix>
];

Basic Security Configuration

# Firewall
networking.firewall.enable = true;

# AppArmor
security.apparmor.enable = true;

# Disable coredumps
systemd.coredump.enable = false;

Hardened Profile

What It Enables

The NixOS hardened profile provides:

  • Hardened Linux kernel with security patches
  • Scudo memory allocator for heap protection
  • Kernel module loading prevention after boot
  • Kernel image protection
  • AppArmor mandatory access control
  • Restricted filesystem module loading
  • Disabled simultaneous multithreading (SMT)
  • Forced page table isolation

Enable Hardened Profile

{ config, pkgs, ... }:

{
  imports = [
    <nixpkgs/nixos/modules/profiles/hardened.nix>
  ];

  # The hardened profile is opinionated
  # You may need to override some defaults
}

In Flakes

{
  nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
    modules = [
      "${nixpkgs}/nixos/modules/profiles/hardened.nix"
      ./configuration.nix
    ];
  };
}

Selective Hardening

# If full hardened profile is too restrictive
# Enable specific hardening features
{
  # Hardened kernel
  boot.kernelPackages = pkgs.linuxPackages_hardened;

  # Memory allocator
  environment.memoryAllocator.provider = "scudo";

  # Lock kernel modules
  security.lockKernelModules = true;

  # Protect kernel image
  security.protectKernelImage = true;

  # AppArmor
  security.apparmor.enable = true;
}

Firewall Configuration

Default Deny

networking.firewall = {
  enable = true;

  # Block all by default
  allowedTCPPorts = [ ];
  allowedUDPPorts = [ ];

  # Allow specific services
  # allowedTCPPorts = [ 22 80 443 ];
};

Service-Specific Rules

networking.firewall = {
  enable = true;

  # SSH
  allowedTCPPorts = [ 22 ];

  # HTTP/HTTPS
  allowedTCPPorts = [ 80 443 ];

  # Custom application
  allowedTCPPorts = [ 8080 ];
  allowedUDPPorts = [ 5353 ];  # mDNS

  # Port ranges
  allowedTCPPortRanges = [
    { from = 8000; to = 8100; }
  ];

  # Allow specific interfaces
  interfaces."eth0".allowedTCPPorts = [ 80 ];
};

Advanced Firewall

networking.firewall = {
  enable = true;

  # Reject instead of drop (faster for local testing)
  rejectPackets = true;

  # Allow ping
  allowPing = true;

  # Custom firewall rules
  extraCommands = ''
    # Rate limit SSH connections
    iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
    iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

    # Log dropped packets
    iptables -A INPUT -j LOG --log-prefix "FIREWALL-DROP: "
  '';
};

AppArmor

Enable AppArmor

{
  security.apparmor = {
    enable = true;

    # Kill unconfined but confinable programs
    killUnconfinedConfinables = true;

    # Load extra profiles
    packages = with pkgs; [
      apparmor-profiles
    ];
  };
}

Custom AppArmor Profiles

{
  security.apparmor = {
    enable = true;

    # Define custom profiles
    policies = {
      "myapp" = {
        enable = true;
        enforce = true;
        profile = ''
          #include <tunables/global>

          /usr/bin/myapp {
            #include <abstractions/base>

            # Allow reading config
            /etc/myapp/** r,

            # Allow writing logs
            /var/log/myapp/** w,

            # Network access
            network inet stream,

            # Deny everything else
          }
        '';
      };
    };
  };
}

Check AppArmor Status

# View loaded profiles
sudo aa-status

# View profile status
sudo aa-enabled

# Complain mode (log instead of enforce)
sudo aa-complain /path/to/program

# Enforce mode
sudo aa-enforce /path/to/program

User and Authentication Security

Strong Password Policies

{
  security.pam.services = {
    # Require strong passwords
    passwd.text = ''
      password required pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1
    '';
  };

  # Password aging
  security.pam.loginLimits = [
    { domain = "*"; type = "hard"; item = "maxlogins"; value = "3"; }
  ];
}

Sudo Configuration

{
  # Require password for sudo
  security.sudo = {
    enable = true;

    # Timeout for password (in minutes)
    extraConfig = ''
      Defaults timestamp_timeout=5

      # Require password for every command
      Defaults !authenticate

      # Log all sudo commands
      Defaults logfile=/var/log/sudo.log
    '';
  };

  # Limit sudo to wheel group
  security.sudo.wheelNeedsPassword = true;
}

SSH Hardening

{
  services.openssh = {
    enable = true;

    settings = {
      # Disable root login
      PermitRootLogin = "no";

      # Disable password authentication
      PasswordAuthentication = false;

      # Only allow key-based auth
      PubkeyAuthentication = true;

      # Disable empty passwords
      PermitEmptyPasswords = false;

      # Disable X11 forwarding
      X11Forwarding = false;

      # Use strong ciphers only
      Ciphers = [ "chacha20-poly1305@openssh.com" "aes256-gcm@openssh.com" ];
      KexAlgorithms = [ "curve25519-sha256" "curve25519-sha256@libssh.org" ];
      Macs = [ "hmac-sha2-512-etm@openssh.com" "hmac-sha2-256-etm@openssh.com" ];

      # Limit authentication attempts
      MaxAuthTries = 3;

      # Client timeout
      ClientAliveInterval = 300;
      ClientAliveCountMax = 2;
    };

    # Allow specific users only
    allowUsers = [ "user1" "user2" ];
  };
}

Systemd Service Hardening

Service Isolation

{
  systemd.services.myservice = {
    serviceConfig = {
      # User/Group isolation
      DynamicUser = true;
      User = "myservice";
      Group = "myservice";

      # Filesystem isolation
      ProtectSystem = "strict";
      ProtectHome = true;
      PrivateTmp = true;
      ReadOnlyPaths = [ "/etc" ];
      ReadWritePaths = [ "/var/lib/myservice" ];

      # Network isolation
      PrivateNetwork = false;  # Set true to disable network
      RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];

      # Kernel isolation
      ProtectKernelTunables = true;
      ProtectKernelModules = true;
      ProtectKernelLogs = true;
      ProtectControlGroups = true;

      # Capabilities
      CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
      AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
      NoNewPrivileges = true;

      # System calls
      SystemCallFilter = [ "@system-service" "~@privileged" ];
      SystemCallArchitectures = "native";

      # Devices
      PrivateDevices = true;
      DevicePolicy = "closed";

      # Memory protection
      MemoryDenyWriteExecute = true;
      LockPersonality = true;
      RestrictRealtime = true;
      RestrictSUIDSGID = true;

      # Namespace
      RestrictNamespaces = true;
    };
  };
}

Analyze Service Security

# Check service security score
systemd-analyze security myservice.service

# Show detailed security analysis
systemd-analyze security --no-pager myservice.service

Application Sandboxing

Firejail

{
  # Install firejail
  environment.systemPackages = with pkgs; [ firejail ];

  # Wrap applications with firejail
  programs.firejail = {
    enable = true;

    # Wrap browsers
    wrappedBinaries = {
      firefox = {
        executable = "${pkgs.firefox}/bin/firefox";
        profile = "${pkgs.firejail}/etc/firejail/firefox.profile";
      };

      chromium = {
        executable = "${pkgs.chromium}/bin/chromium";
        profile = "${pkgs.firejail}/etc/firejail/chromium.profile";
      };
    };
  };
}

Flatpak Sandboxing

{
  services.flatpak.enable = true;

  # Use Flatpak for untrusted applications
  # Provides strong sandboxing via Bubblewrap
}

Kernel Hardening

Kernel Parameters

{
  boot.kernel.sysctl = {
    # Prevent kernel pointer leaks
    "kernel.kptr_restrict" = 2;

    # Restrict dmesg to root
    "kernel.dmesg_restrict" = 1;

    # Restrict loading TTY line disciplines
    "dev.tty.ldisc_autoload" = 0;

    # Disable kexec
    "kernel.kexec_load_disabled" = 1;

    # Restrict performance events
    "kernel.perf_event_paranoid" = 3;

    # Restrict BPF to CAP_BPF
    "kernel.unprivileged_bpf_disabled" = 1;

    # Enable ASLR
    "kernel.randomize_va_space" = 2;

    # Protect symlinks/hardlinks
    "fs.protected_symlinks" = 1;
    "fs.protected_hardlinks" = 1;
    "fs.protected_fifos" = 2;
    "fs.protected_regular" = 2;

    # Network security
    "net.core.bpf_jit_harden" = 2;
    "net.ipv4.conf.all.rp_filter" = 1;
    "net.ipv4.conf.default.rp_filter" = 1;
    "net.ipv4.conf.all.accept_source_route" = 0;
    "net.ipv6.conf.all.accept_source_route" = 0;
    "net.ipv4.conf.all.send_redirects" = 0;
    "net.ipv4.conf.default.send_redirects" = 0;
    "net.ipv4.conf.all.accept_redirects" = 0;
    "net.ipv6.conf.all.accept_redirects" = 0;
    "net.ipv4.tcp_syncookies" = 1;
    "net.ipv4.icmp_echo_ignore_broadcasts" = 1;
  };
}

Blacklist Kernel Modules

{
  boot.blacklistedKernelModules = [
    # Disable uncommon network protocols
    "dccp"
    "sctp"
    "rds"
    "tipc"

    # Disable uncommon filesystems
    "cramfs"
    "freevxfs"
    "jffs2"
    "hfs"
    "hfsplus"
    "udf"

    # Disable legacy/unused
    "bluetooth"
    "btusb"
  ];
}

Secrets Management

Use agenix

{
  # Never store secrets in plain text
  # Use agenix for encrypted secrets

  age.secrets.database-password = {
    file = ../secrets/db-password.age;
    owner = "postgres";
    mode = "0400";
  };

  # Reference secret path (not content!)
  services.postgresql.authentication = ''
    # Use: config.age.secrets.database-password.path
  '';
}

Prevent Secrets in Nix Store

{
  # Don't do this:
  # services.myapp.apiKey = "secret123";  # BAD! In nix store!

  # Do this:
  systemd.services.myapp = {
    serviceConfig = {
      EnvironmentFile = config.age.secrets.api-key.path;
    };
  };
}

Monitoring and Auditing

Audit Framework

{
  # Enable audit framework
  security.audit.enable = true;

  security.auditd.enable = true;

  # Audit rules
  security.audit.rules = [
    # Monitor sensitive files
    "-w /etc/passwd -p wa -k passwd_changes"
    "-w /etc/shadow -p wa -k shadow_changes"
    "-w /etc/sudoers -p wa -k sudoers_changes"

    # Monitor authentication
    "-w /var/log/auth.log -p wa -k auth_log"

    # Monitor network changes
    "-a always,exit -F arch=b64 -S socket -S connect -k network"
  ];
}

ClamAV Antivirus

{
  services.clamav = {
    daemon.enable = true;
    updater.enable = true;
  };

  # Scan on schedule
  systemd.services.clamav-scan = {
    description = "ClamAV system scan";
    serviceConfig = {
      Type = "oneshot";
      ExecStart = "${pkgs.clamav}/bin/clamdscan --multiscan --fdpass /home";
    };
  };

  systemd.timers.clamav-scan = {
    wantedBy = [ "timers.target" ];
    timerConfig = {
      OnCalendar = "daily";
      Persistent = true;
    };
  };
}

Network Security

OpenSnitch Firewall

{
  # Application-level firewall
  services.opensnitch = {
    enable = true;

    settings = {
      DefaultAction = "deny";
      DefaultDuration = "until restart";
    };
  };
}

VPN Configuration

{
  # WireGuard VPN
  networking.wireguard.interfaces = {
    wg0 = {
      ips = [ "10.100.0.2/24" ];
      privateKeyFile = config.age.secrets.wireguard-key.path;

      peers = [{
        publicKey = "server-public-key";
        endpoint = "vpn.example.com:51820";
        allowedIPs = [ "0.0.0.0/0" ];
        persistentKeepalive = 25;
      }];
    };
  };

  # Route all traffic through VPN
  networking.firewall.checkReversePath = "loose";
}

Security Best Practices

  1. Use the hardened profile: Start with security-focused defaults
  2. Default deny firewall: Only allow required ports
  3. Enable AppArmor: Mandatory access control for services
  4. Harden SSH: Disable password auth, use keys only
  5. Systemd hardening: Use service isolation features
  6. Encrypt secrets: Never store secrets in Nix store
  7. Regular updates: Keep system and packages current
  8. Minimal installation: Don’t install unnecessary packages
  9. Monitor logs: Check audit logs regularly
  10. Principle of least privilege: Grant minimum required permissions

Testing Security Configuration

Check Open Ports

# Local ports
ss -tulpn

# From remote
nmap hostname

Verify AppArmor

# Check status
sudo aa-status

# View profile logs
sudo journalctl -u apparmor

Test Service Hardening

# Analyze security
systemd-analyze security service-name

# Check if service can access filesystem
sudo -u service-user cat /etc/shadow  # Should fail

Common Hardening Pitfalls

  1. Breaking functionality: Hardening can break applications

    • Test thoroughly after changes
    • Use systemd-analyze security to check impact
  2. Performance overhead: Security features have cost

    • Hardened kernel is slower
    • Profile before/after
  3. Update challenges: Hardening can complicate updates

    • Document all customizations
    • Test updates in VM first
  4. Complexity: Too many security layers

    • Start simple, add incrementally
    • Understand each feature

Resources


Troubleshoot - Common Issues and Solutions

Common Nix issues, error messages, and solutions.

When to Use

  • “nix error”
  • “troubleshoot nix”
  • “nix build failing”
  • “fix nix issue”

Common Errors

Hash Mismatch

Error:

error: hash mismatch in fixed-output derivation
  specified: sha256-AAAA...
  got:        sha256-BBBB...

Solution:

# Copy the "got" hash
src = fetchFromGitHub {
  owner = "owner";
  repo = "repo";
  rev = "v1.0.0";
  hash = "sha256-BBBB...";  # Use hash from error
};

Get Hash Correctly:

# For GitHub
nix-prefetch-github owner repo --rev v1.0.0

# For URLs
nix-prefetch-url https://example.com/file.tar.gz

# For Git
nix-prefetch-git https://git.example.com/repo.git --rev commit-hash

Infinite Recursion

Error:

error: infinite recursion encountered

Common Causes:

# 1. Self-referencing attribute
{
  x = x;  # Infinite recursion!
}

# 2. Circular dependency
{
  a = b;
  b = a;  # Infinite recursion!
}

# 3. Overlay recursion
final: prev: {
  mypackage = prev.mypackage.override {  # Infinite!
    # ...
  };
}

Solutions:

# Use lib.mkDefault or lib.mkForce
{ lib, ... }:
{
  value = lib.mkDefault something;
}

# Break overlay recursion with super
final: prev: {
  mypackage = (prev.mypackage.override {
    # ...
  }).overrideAttrs (old: {
    # ...
  });
}

# Use rec carefully
rec {
  x = 1;
  y = x + 1;  # OK
}

Attribute Not Found

Error:

error: attribute 'foo' missing
error: undefined variable 'bar'

Debug:

# Check what attributes exist
nix eval .#nixosConfigurations.hostname --apply builtins.attrNames

# Check nested path
nix eval .#nixosConfigurations.hostname.config.services --apply builtins.attrNames

# Use --show-trace
nix eval .#value --show-trace

Common Fixes:

# Check spelling
services.nginx.enable = true;  # Not nginX or nginx

# Import missing module
imports = [ ./missing-module.nix ];

# Check if package exists
nix search nixpkgs package-name

File Not Found

Error:

error: getting status of '/nix/store/.../file': No such file or directory
error: path '/path/to/file' does not exist

Solutions:

# Use relative paths in flakes
src = ./path/to/file;  # Not /absolute/path

# Check file exists
# ls path/to/file

# In pure eval, paths must be relative
# Don't use: /home/user/file
# Use: ./file or ./relative/path

Import from Derivation (IFD)

Error:

error: cannot build '/nix/store/...' during evaluation

Cause: Import from Derivation - importing result of a build

Workarounds:

# Avoid when possible
# Bad:
let
  generated = import (pkgs.runCommand "gen" {} ''
    echo "{ value = 42; }" > $out
  '');
in
  generated.value

# Good: Use builtins or pure Nix
let
  generated = { value = 42; };
in
  generated.value

Restricted Mode / Pure Eval

Error:

error: access to absolute path '/home/...' is forbidden in pure eval mode
error: cannot look up '<nixpkgs>' in pure evaluation mode

Solutions:

# Use relative paths
path = ./file.nix;  # Not /absolute/path

# Use flake inputs instead of <nixpkgs>
{ inputs, ... }:
  inputs.nixpkgs.legacyPackages.x86_64-linux.hello

# For development, use --impure
nix build --impure

Build Failures

Compilation Errors

Check Build Log:

# View last build log
nix log .#package

# Keep build directory on failure
nix build .#package --keep-failed

# Inspect failed build
cd /tmp/nix-build-package-*.drv-0/
cat build.log
ls -la

Common Issues:

# Missing dependencies
# Add to buildInputs or nativeBuildInputs

# Wrong C/C++ compiler
# Set CC, CXX environment variables

# Missing pkg-config
# Add pkg-config to nativeBuildInputs

# Library not found
# Add to buildInputs and check PKG_CONFIG_PATH

Test Failures

Skip Tests Temporarily:

stdenv.mkDerivation {
  # ...
  doCheck = false;  # Disable tests
}

Debug Tests:

# Run tests manually
nix develop .#package
unpackPhase
cd $sourceRoot
configurePhase
buildPhase
checkPhase  # Run tests with full output

Missing Files in Output

Check Output:

# What's in the output?
nix build .#package
tree result/
ls -R result/

# Check if files were created during build
nix build .#package --keep-failed
cd /tmp/nix-build-*/
find . -name "expected-file"

Fix Install Phase:

installPhase = ''
  runHook preInstall

  mkdir -p $out/bin
  cp myapp $out/bin/

  # Install other files
  mkdir -p $out/share/doc
  cp README.md $out/share/doc/

  runHook postInstall
'';

Runtime Issues

Executable Not Found

Error:

bash: command not found

Check:

# Is package installed?
which command-name

# Check package output
nix build .#package
ls result/bin/

# Check PATH
echo $PATH

# Install package
nix profile install .#package

Library Not Found

Error:

error while loading shared libraries: libfoo.so.1: cannot open shared object file

Solutions:

# Use autoPatchelfHook
nativeBuildInputs = [ autoPatchelfHook ];

# Add runtime dependencies
buildInputs = [ libfoo ];

# Check dependencies
ldd result/bin/program

# Patch manually
patchelf --set-rpath ${lib.makeLibraryPath [ libfoo ]} $out/bin/program

Permission Denied

Check Permissions:

# File permissions in store
ls -l result/

# Files should be readable
# Executables should have +x

Fix:

postInstall = ''
  chmod +x $out/bin/myapp
'';

Disk Space Issues

Out of Disk Space

Check Space:

# Check /nix/store size
du -sh /nix/store

# Check total disk usage
df -h

# Find large paths
nix path-info --closure-size .#package | sort -h

Clean Up:

# Delete old generations
nix-collect-garbage -d

# Delete generations older than 30 days
nix-collect-garbage --delete-older-than 30d

# Optimize store (deduplicate)
nix-store --optimize

# Delete specific paths
nix-store --delete /nix/store/...-package

Garbage Collection Issues

Error:

error: cannot delete path '...' because it is in use by '...'

Solutions:

# Find what's using the path
nix-store --query --roots /nix/store/...-package

# Remove from profiles
nix profile remove package-name

# Delete old generations first
nix-env --delete-generations old
nix-collect-garbage

Network Issues

Download Failures

Error:

error: unable to download 'https://...'
error: curl error: Connection timeout

Solutions:

# Check network
ping example.com

# Try with different substituter
nix build --substituters https://cache.nixos.org

# Build without network (use only local)
nix build --offline

# Build without binary cache
nix build --no-substitute

Binary Cache Issues

Error:

error: cannot add path '...' to the store
warning: ignoring substitute for '...'

Solutions:

# Add cache manually
nix build --substituters https://cache.nixos.org \
  --trusted-public-keys cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=

# Configure in nix.conf
# trusted-substituters = https://cache.nixos.org

# Use cachix
cachix use cachename

Configuration Issues

Syntax Errors

Error:

error: syntax error, unexpected IF
error: undefined variable 'if'

Common Mistakes:

# 1. Missing semicolon
{
  option1 = value1
  option2 = value2;  # ERROR: missing ; after value1
}

# 2. Wrong if syntax
if condition value1 value2  # ERROR: missing 'then' and 'else'
if condition then value1 else value2  # Correct

# 3. Missing 'in'
let x = 1; x + 1  # ERROR: missing 'in'
let x = 1; in x + 1  # Correct

# 4. Comments
/* Multi-line comment */
# Single-line comment

Module Conflicts

Error:

error: The option `services.foo.enable' is defined multiple times

Solutions:

# Use lib.mkForce to override
services.foo.enable = lib.mkForce true;

# Or remove duplicate definition
# Check all imported modules

# Use lib.mkMerge for lists
services.foo.extraConfig = lib.mkMerge [
  (lib.mkIf condition1 [ value1 ])
  (lib.mkIf condition2 [ value2 ])
];

Type Mismatches

Error:

error: value is a set while a string was expected
error: value is a string while a list was expected

Solutions:

# Check types
builtins.typeOf value

# Convert as needed
toString 42  # "42"
lib.splitString "," "a,b,c"  # [ "a" "b" "c" ]
[ value ]  # Wrap in list

# Check option type
# Look at option definition to see expected type

System Issues

System Won’t Boot

Recovery:

# 1. Boot to previous generation
# Select older generation in bootloader menu

# 2. From rescue system
mount /dev/sdX /mnt
mount /dev/sdY /mnt/boot
nixos-enter --root /mnt

# Rollback
nixos-rebuild switch --rollback

# Or specific generation
/nix/var/nix/profiles/system-42-link/bin/switch-to-configuration switch

Service Failures

Debug:

# Check service status
systemctl status service-name

# View logs
journalctl -u service-name -n 50

# View service definition
systemctl cat service-name

# Check generated config
cat /etc/systemd/system/service-name.service

Common Issues:

# Wrong user
systemd.services.myservice.serviceConfig.User = "correct-user";

# Missing dependency
systemd.services.myservice.after = [ "network.target" ];

# Wrong paths
# Use full store paths or ${}
ExecStart = "${pkgs.myapp}/bin/myapp";

Home-Manager Issues

Error:

error: collision between files

Solutions:

# Let home-manager manage conflicts
home.file."conflict".source = ./file;

# Force overwrite
home.file."conflict" = {
  source = ./file;
  force = true;
};

# Disable conflicting package
home.packages = lib.filter (p: p != pkgs.conflicting) config.home.packages;

Performance Issues

Slow Evaluation

Profile:

# Time evaluation
time nix eval .#nixosConfigurations.hostname.config.system.build.toplevel

# Show stats
nix eval --show-stats .#value

Optimize:

# Avoid expensive operations in hot paths
# Use builtins when possible
# Minimize use of import
# Cache computed values

Slow Builds

Speed Up:

# Use more cores
nix build --cores $(nproc)

# Parallel jobs
nix build --max-jobs auto

# Use binary caches
nix build --substituters https://cache.nixos.org

# Build without downloads
nix build --offline

Emergency Recovery

Corrupted Nix Store

Check:

# Verify store
nix-store --verify --check-contents

# Repair
nix-store --verify --repair

Locked Nix Database

Error:

error: cannot open Nix database: database is locked

Fix:

# Stop nix-daemon
systemctl stop nix-daemon

# Remove lock
rm /nix/var/nix/db/db.lock

# Restart daemon
systemctl start nix-daemon

Full Disk

Emergency Clean:

# Delete old generations
sudo nix-env --delete-generations +5

# Garbage collect
sudo nix-collect-garbage -d

# Optimize
sudo nix-store --optimize

# Remove build artifacts
rm -rf /tmp/nix-build-*

Resources