Stumbling into activating x11grab in standard ffmpeg

System: NixOS 26.05 x86_64

WM: Xfwm4 (X11)

CPU: Intel N150

GPU: Integrated Graphics

I wrote this intending to ask for help, but I eventually figured it out on my own. After a week of hunting through the wiki’s, a bunch of unofficial wikis on increasingly shady domains, youtube videos, artificial stupidity, and, as a last resort, Stackoverflow and Reddit. It’s less of a guide and more of a catalog of how I eventually found my answer. Keep in mind I tried my usual approach of skimming the reference manual before reading source code to try learning Nix. I was confident having played with functional paradims in Lua, Javascript, multiple Schemes and even a little Haskell.

I tried using ffmpeg to screen capture as I’ve done on my previous system. However, I received this error informing me that x11grab was unavailable.

$ ffmpeg -video_size 1366x768 -framerate 25 -f x11grab -i :0.0 output.mkv
ffmpeg version 8.1.1 Copyright (c) 2000-2026 the FFmpeg developers
  built with gcc 15.2.0 (GCC)
  configuration: --disable-static --prefix=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1 --target_os=linux --arch=x86_64 --pkg-config=pkg-config --enable-gpl --enable-version3 --disable-nonfree --disable-static --enable-shared --enable-pic --disable-thumb --disable-small --enable-runtime-cpudetect --disable-gray --enable-swscale-alpha --enable-hardcoded-tables --enable-safe-bitstream-reader --enable-pthreads --disable-w32threads --disable-os2threads --enable-network --enable-pixelutils --datadir=/nix/store/50jahvv3gz6awqi0vh90sbyz894j95xh-ffmpeg-8.1.1-data/share/ffmpeg --enable-ffmpeg --enable-ffplay --enable-ffprobe --bindir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1-bin/bin --enable-avcodec --enable-avdevice --enable-avfilter --enable-avformat --enable-avutil --enable-swresample --enable-swscale --libdir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1-lib/lib --incdir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1-dev/include --enable-doc --enable-htmlpages --enable-manpages --mandir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1-man/share/man --enable-podpages --enable-txtpages --docdir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-ffmpeg-8.1.1-doc/share/doc/ffmpeg --enable-alsa --enable-amf --enable-libaom --disable-libaribb24 --disable-libaribcaption --enable-libass --disable-avisynth --enable-libbluray --disable-libbs2b --enable-bzlib --disable-libcaca --disable-libcdio --disable-libcelt --disable-chromaprint --disable-libcodec2 --disable-cuda --enable-cuda-llvm --disable-cuda-nvcc --enable-cuvid --enable-libdav1d --disable-libdavs2 --disable-libdc1394 --enable-libdrm --disable-libdvdnav --disable-libdvdread --disable-libfdk-aac --enable-ffnvcodec --disable-libflite --enable-fontconfig --enable-libfontconfig --enable-libfreetype --disable-frei0r --enable-libfribidi --disable-libgme --enable-gmp --enable-gnutls --disable-libgsm --enable-libharfbuzz --enable-iconv --disable-libilbc --disable-libjack --disable-libjxl --disable-libkvazaar --disable-ladspa --disable-liblc3 --disable-liblcevc-dec --disable-lcms2 --enable-lzma --disable-metal --disable-libmfx --disable-libmodplug --enable-libmp3lame --disable-libmysofa --disable-libnpp --enable-nvdec --enable-nvenc --disable-openal --enable-liboapv --enable-opencl --disable-libopencore-amrnb --disable-libopencore-amrwb --disable-opengl --disable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-libopus --disable-libplacebo --enable-libpulse --disable-libqrencode --disable-libquirc --disable-librav1e --enable-librist --disable-librtmp --disable-librubberband --disable-libsmbclient --enable-sdl2 --disable-libshaderc --disable-libshine --disable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --disable-librsvg --enable-libsvtav1 --disable-libtensorflow --enable-libtheora --disable-libtwolame --disable-libuavs3d --enable-libv4l2 --enable-v4l2-m2m --enable-vaapi --enable-vdpau --disable-libvpl --enable-libvidstab --disable-libvmaf --disable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-vulkan --disable-libvvenc --enable-libwebp --disable-whisper --enable-libx264 --enable-libx265 --disable-libxavs --disable-libxavs2 --disable-libxcb --disable-libxcb-shape --disable-libxcb-shm --disable-libxcb-xfixes --disable-libxevd --disable-libxeve --disable-xlib --enable-libxml2 --enable-libxvid --enable-libzimg --enable-zlib --disable-libzmq --enable-libzvbi --disable-debug --enable-optimizations --disable-extra-warnings --disable-stripping
  libavutil      60. 26.101 / 60. 26.101
  libavcodec     62. 28.101 / 62. 28.101
  libavformat    62. 12.101 / 62. 12.101
  libavdevice    62.  3.101 / 62.  3.101
  libavfilter    11. 14.101 / 11. 14.101
  libswscale      9.  5.101 /  9.  5.101
  libswresample   6.  3.101 /  6.  3.101
[in#0 @ 0x5e312e40ccc0] Unknown input format: 'xllgrab'
Error opening input file :0.0.
Error opening input files: Invalid argument

What stood out to me was the –disable-xlib flag. I don’t remember doing that. I assumed at the time that it was related to x11grab. I then checked devices with ffmpeg -devices

Devices:
 D. = Demuxing supported
 .E = Muxing supported
 ---
 DE alsa            ALSA audio output
 DE fbdev           Linux framebuffer
 D  kmsgrab         KMS screen capture
 D  lavfi           Libavfilter virtual input device
 DE oss             OSS (Open Sound System) playback
 DE pulse           Pulse audio output
 DE video4linux2,v4l2 Video4Linux2 output device

Never heard of kmsgrab before. Tried replacing it with x11grab and got a similar error. The ffmpeg manual tells me that kmsgrab needs CAP_SYS_ADMIN or DRM master to function. The former is a super user privilege, which even without the capabilities man page’s warning strikes me as a bad idea. Looking up the later leads me to the drm man page which is of little help since it has multiple broken links (even on mirror sites) with the one functioning link leading to a library page (3) instead of an executable program (1).

I then looked it up in the packages. Wasn’t sure what I was looking at as the descriptions were identical with each package. Swapped to options search and there’s nothing pertaining to ffmpeg itself, just other packages that depend on ffmpeg. Found a package called capture which seemed to rely on ffmpeg based on the source. grabbed it. Still no x11grab.

Looking at the package source, xlib is listed a few times as an optional for the full variant of ffmpeg. The only warning was to not use overrideAttr, so I tried using stuff like

environment.systemPackages = with pkgs;[
...
(ffmpeg.override{withfull = true;})
...
];

Not a package error. I thought maybe I was using it wrong, so I looked at the nixpkg manual. Ctrl+f gave 568 references. Ok, lets try “overrideAttr“ just to see what its about. 78 references. “overriding” at least had a name drop in the anemic table of contents, so I looked at that.

pkgs.foo.override {
  arg1 = val1;
  arg2 = val2; # ...
}

So I’m not supposed to use the surrounding parenthesis?

ffmpeg.override{xlib = true;}

Not a package error.

So back to trying to figure out how activate these feature flags. In the source I see enableFeature and optionals, both are part of lib according to the nixpkgs manual which I already have as an import. Neither fit my need, as I’m working with a package. The comments warned against using overrideAttr, so lets try just overide…

(ffmpeg.override{withXlib = true;})

Returned errors about this not being a package. I tried putting it inside the nixpkgs.config. No dice.

I took another look at the package search. This time I saw “fmpeg-full” and “ffmpeg-headless“ and the correlation was now obvious. While that technically satisfies my needs by granting xlib (thus x11grab), ffmpeg-full also comes with tons of baggage I don’t need like cuda support. Sides, even the package comments suggest only activating the options that I need rather than using full.

Eventually I had a completely different issue (lua couldn’t find the path for packages) and noticed the pkgs prefix in the solution. So I randomly decided to append pkgs…

(pkgs.ffmpeg.override{withXlib = true;})

It started building ffmpeg from source. This was a scope issue this whole time? I tried looking at the nix manual to figure out the scope rules…

A scope in the Nix language is a dictionary keyed by name, mapping each name to an expression and a definition type.

Excuse me? In every other language I’ve used, scope is where a variable or function definition is valid. So even if I thought to look this up earlier, I would have his another wall.

After waiting for ffmpeg to build from source, I ffmpeg -devices again and still no x11grab. I look it up and… it’s been deprecated since v3.3 nearly a decade ago? And it was the Xcb flags I should have been looking for? ¿Que demonios de pasa? How many programs rely on this functionality? I just used it on my last system install late last year. So I update my config again…

(pkgs.ffmpeg.override{withXlib = true; withXcb = true;})

Wait another 20 minutes. Ran ffmpeg -devices one more time. Saw my beloved x11grab. ran my one liner again and… now the mouse is missing. Looked at the output. –disable-libxcb-xfixes, which enables mouse recording. Looks like I misread this line:

withXcb ? withXcbShm || withXcbxfixes || withXcbShape, # X11 grabbing using XCB

As “if withXcb is true, then withXcbShm or withXcbxfixes or withXcbShape will be true“. This actually means “withXcb will be true if any of the following are true“. Coming from C I thought something looked weird about these if statements. One more change…

(pkgs.ffmpeg.override{
withXcbxfixes = true;
withXcbShape = true;
withXcbShm = true;
})

Rebuilt again, and with one more line:

$ ffmpeg -video_size 1366x768 -framerate 25 -f x11grab -i :0.0 please-work-for-the-love-of-odin.mkv

I finally got my screen recorder, and as I have a good idea of how to fix capture. After a nap. I haven’t slept in days dealing with this mess.

4 Likes

For the record, since you seem to be taking the wrong learnings from this, that was almost definitely not actually the issue.

Whether you lead with pkgs or ffmpeg only matters if you don’t have an ffmpeg variable, which given that you didn’t have an obvious “no such variable” error you probably do.

I don’t have a crystal ball, so I can’t see your code and tell you what, but you must have fixed something else.

2 Likes

Well now I’m even more confused. My configuration file at the time of writing doesn’t have a ffmpeg variable besides the one provided by environment.systemPackages.pkgs. It does have some of the nonsense I forgot to write above, like ((enableFeature true "Xlib") ffmpeg).
Anyway, I tried removing pkgs. from ffmpeg. System compiled. Flags were fine.
Tried the same with luajit…

LuaJIT 2.1.1774638290 -- Copyright (C) 2005-2026 Mike Pall. https://luajit.org/
JIT: ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse
> http = require("http")
stdin:1: module 'http' not found:
        no field package.preload['http']
        no file './http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/luajit-2.1/http.lua'
        no file '/usr/local/share/lua/5.1/http.lua'
        no file '/usr/local/share/lua/5.1/http/init.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http/init.lua'
        no file './http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/luajit-2.1/http.lua'
        no file '/usr/local/share/lua/5.1/http.lua'
        no file '/usr/local/share/lua/5.1/http/init.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http/init.lua'
        no file './http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/luajit-2.1/http.lua'
        no file '/usr/local/share/lua/5.1/http.lua'
        no file '/usr/local/share/lua/5.1/http/init.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http.lua'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/share/lua/5.1/http/init.lua'
        no file '/nix/store/0d5qw2syxr4r7flm3ng1sb02dzci5d6h-luajit-2.1.1774638290-env/share/lua/5.1/http.lua'
        no file '/nix/store/0d5qw2syxr4r7flm3ng1sb02dzci5d6h-luajit-2.1.1774638290-env/share/lua/5.1/http/init.lua'
        no file './http.so'
        no file '/usr/local/lib/lua/5.1/http.so'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/lib/lua/5.1/http.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
        no file './http.so'
        no file '/usr/local/lib/lua/5.1/http.so'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/lib/lua/5.1/http.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
        no file './http.so'
        no file '/usr/local/lib/lua/5.1/http.so'
        no file '/nix/store/pmj0a9agz9ww0y8sifpmalfg6mrv8vrb-luajit-2.1.1774638290/lib/lua/5.1/http.so'
        no file '/usr/local/lib/lua/5.1/loadall.so'
        no file '/nix/store/0d5qw2syxr4r7flm3ng1sb02dzci5d6h-luajit-2.1.1774638290-env/lib/lua/5.1/http.so'
stack traceback:
        [C]: in function 'require'
        stdin:1: in main chunk
        [C]: at 0x5ff98f3a7450

Tried removing pkgs. from that and… the same thing happened? I swore this was just working earlier!

Share the exact diffs? Are you 100% certain you’re not deploying a symlink to a different config or something?

1 Like

Apologies for the late response. This a diff for my current commit and initial one.

git diff f68d6c2d5b372486a1fa1ead983f4bf545a04210
index fd9819a..3576a10 100644
--- a/configuration.nix
+++ b/configuration.nix
@@ -196,7 +196,7 @@
     feh
     #((enableFeature true "Xlib") ffmpeg )
     #ffmpeg-full
-    (pkgs.ffmpeg.override{
+    (ffmpeg.override{
     withXcbShm = true;
     withXcbxfixes = true;
     withXcbShape = true;
@@ -214,7 +214,7 @@
     htop
     inklecate # Some games need rebuilding in glorious scheme
     krita
-    (pkgs.luajit.withPackages(ps: with ps;[xml2lua http cjson])) # May move this to the projects that need it.
+    (lua5_4.withPackages(ps: with ps;[xml2lua http cjson])) # May move this to the projects that need it.
     man-db
     man-pages
     man-pages-posix

I should have initialized git the second I got logged in the first time, but it’s a little late for that. I’ll also include the other diffs, though they’re full of noise from attempting to sync with gitlab.

Vomit from syncing
diff --git a/configuration.nix b/configuration.nix
new file mode 100644
index 0000000..3576a10
--- /dev/null
+++ b/configuration.nix
@@ -0,0 +1,290 @@
+# Edit this configuration file to define what should be installed on
+# your system.  Help is available in the configuration.nix(5) man page
+# and in the NixOS manual (accessible by running ‘nixos-help’).
+
+{ config, pkgs, lib, ... }:
+#let
+#  home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-26.05.tar.gz;
+#in
+{
+  imports =
+    [ # Include the results of the hardware scan.
+      ./hardware-configuration.nix
+      #(import "${home-manager}/nixos")
+    ];
+
+  # Bootloader.
+  boot.loader.systemd-boot.enable = true;
+  boot.loader.efi.canTouchEfiVariables = true;
+
+  # Use latest kernel.
+  boot.kernelPackages = pkgs.linuxPackages_latest;
+
+  networking.hostName = "midori"; # Define your hostname.
+  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
+
+  # Configure network proxy if necessary
+  # networking.proxy.default = "http://user:password@proxy:port/";
+  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
+
+  programs.nix-ld.enable = true;
+
+  # Enable networking
+  networking.networkmanager.enable = true;
+
+  # Set your time zone.
+  time.timeZone = "America/Nassau";
+
+  # Select internationalisation properties.
+  i18n.defaultLocale = "en_US.UTF-8";
+
+  # Enable the X11 windowing system.
+  services.xserver.enable = true;
+
+  # In case of Segmentation Fault
+  systemd.coredump.enable = true;
+
+  # Handle laptop lid switch
+  services.logind.settings.Login = {
+    HandleLidSwitch = "suspend";
+    HandleLidSwitchExternalPower = "suspend";
+    HandleLidSwitchDocked = "ignore";
+  };
+
+  # XFCE Enviroment
+  services.xserver = {
+    desktopManager = {
+      xterm.enable = true;
+      xfce.enable = true;
+      };
+  };
+  services.displayManager.defaultSession = "xfce";
+
+  services.blueman.enable = true;
+
+  hardware.sane.enable = true; # Scanner support
+  hardware.sane.extraBackends = [pkgs.hplipWithPlugin];
+
+  hardware.opentabletdriver.enable = true;
+  hardware.uinput.enable = true;
+  hardware.bluetooth = {
+    enable = true;
+    powerOnBoot = true;
+  };
+  boot.kernelModules = ["uinput"];
+
+  environment.xfce.excludePackages = [
+    pkgs.mousepad
+    pkgs.parole
+    pkgs.ristretto
+    pkgs.xfce4-taskmanager
+    pkgs.xfce4-terminal
+  ];
+  # Configure keymap in X11
+  services.xserver.xkb = {
+    layout = "us";
+    variant = "";
+  };
+
+  # Enable CUPS to print documents.
+  services.printing.enable = true;
+
+  # Enable sound with pipewire.
+  services.pulseaudio.enable = false;
+  security.rtkit.enable = true;
+  services.pipewire = {
+    enable = true;
+    alsa.enable = true; # Needed for Raylib stuff
+    alsa.support32Bit = true;
+    pulse.enable = true;
+  };
+
+  # Enable touchpad support (enabled default in most desktopManager).
+  # services.xserver.libinput.enable = true;
+
+  # Define a user account. Don't forget to set a password with ‘passwd’.
+  users.users.emerald = {
+    isNormalUser = true;
+    description = "Emerald Random";
+    extraGroups = [ "networkmanager" "wheel" "scanner" "lp"];
+    packages = with pkgs; [
+    #  thunderbird
+    ];
+  };
+  #home-manager.users.emerald = {pkgs, ...}:{
+  #  home.packages = [pkgs.neovim pkgs.markdown-oxide];
+  #  programs.bash.enable = true;
+  #  programs.neovim = {
+  #    enable = true;
+  #    defaultEditor = true;
+  #    vimAlias = true;
+  #    initLua = "
+  #      -- Numbers
+  #      vim.wo.number = true
+  #      vim.wo.relativenumber = true
+  #
+  #      -- Indentation
+  #      vim.bo.tabstop = 4
+  #      vim.bo.shiftwidth = 4
+  #      vim.bo.softtabstop = 4
+  #      vim.bo.autoindent = true
+  #      vim.bo.smartindent = true
+  #      vim.bo.expandtab = true
+#
+ #       -- Search
+  #      vim.o.ignorecase = true
+  #      vim.o.smartcase = true
+  #      vim.o.incsearch = true
+  #
+  #      -- Random Stuff
+  #      vim.wo.linebreak = true
+  #      vim.wo.breakindent = true
+  #      vim.wo.scrolloff = 8
+
+  #      -- lsp's
+  #      vim.lsp.config('nixd', {})
+  #      vim.lsp.config('zls', {})
+  #      vim.lsp.config('lua-lsp', {})
+  #      vim.lsp.config('guile-lsp-server', {})
+  #      vim.lsp.enable({'nixd', 'zls', 'lua-lsp', 'guile-lsp-server'})
+  #    ";
+  #    configure = {
+  #      customRC = ''
+       #      filetype plugin indent on
+  #      autocmd Filetype nix setlocal softtabstop=2 tabstop=2 shiftwidth=2
+  #      autocmd Filetype markdown setlocal spell
+       #      syntax on
+       # set wrap
+       # set showcmd
+  #   colorscheme vim
+  #     '';
+  #   };
+  #  };
+  #  programs.mpv = {
+  #    enable = true;
+  #    config = {
+  #      audio-pitch-correction = false;
+  #      ytdl-format = "res:720+ba";
+  #    };
+  #  };
+  #  home.stateVersion = "25.11"; # Don't touch this!
+  #};
+
+
+  # Allow unfree packages
+  nixpkgs.config = {
+    allowUnfree = true;
+    # ffmpeg = { variant = "full";};
+  };
+
+  # List packages installed in system profile. To search, run:
+  # $ nix search wget
+
+  environment.systemPackages = with pkgs; [
+    audacity
+    p7zip
+    binutils-unwrapped
+    # blender # Sculpting and video editing
+    blueman
+    bluez
+    brave
+    ccls
+    courier-prime
+    comic-neue
+    comic-mono
+    fastfetch
+    feh
+    #((enableFeature true "Xlib") ffmpeg )
+    #ffmpeg-full
+    (ffmpeg.override{
+    withXcbShm = true;
+    withXcbxfixes = true;
+    withXcbShape = true;
+    })
+    file # Don't know why this isn't a default pkg
+    freetube
+    ghostty # Terminal
+    git
+    glibc
+    gnumake # Until I can get more confident in zig build
+    groff
+    guile # Functional programming is a virus I embrace
+    guile-lsp-server
+    perf
+    htop
+    inklecate # Some games need rebuilding in glorious scheme
+    krita
+    (lua5_4.withPackages(ps: with ps;[xml2lua http cjson])) # May move this to the projects that need it.
+    man-db
+    man-pages
+    man-pages-posix
+    mpv
+    nhentai # Entertainment
+    nixd
+    nixpkgs-fmt
+    optipng #Shrink png's losslessly
+    markdown-oxide
+    presenterm # Slideshows in the terminal
+    rtorrent
+    sent # Minimal Slideshows writen in md-like syntax
+    wget # Don't remember the last time I used this
+    yt-dlp # Download videos I like
+    xsane
+    zathura #Comics and pdf viewer
+    #zig # Build sytstem and language
+    zls
+
+  ];
+
+  programs.neovim = {
+    enable = true;
+    defaultEditor = true;
+    vimAlias = true;
+    configure = {
+       customRC = ''
+     set tabstop=4
+        set shiftwidth=4
+        set expandtab
+        filetype plugin indent on
+        syntax on
+     set nu rnu
+        set wrap
+        set showcmd
+     colorscheme vim
+     highlight Normal guibg=none
+     highlight NonText guibg=none
+     highlight Normal ctermbg=none
+     highlight NonText ctermbg=none
+       '';
+    };
+  };
+
+  nix.settings.experimental-features = [ "nix-command" "flakes" ];
+
+  environment.variables.EDITOR = "nvim";
+
+  fonts.packages = with pkgs; [
+    courier-prime
+    comic-neue
+    comic-mono
+    noto-fonts
+    noto-fonts-cjk-sans
+    noto-fonts-color-emoji
+    fira-code
+    fira-code-symbols
+    dina-font
+  ];
+
+
+  # Enable the OpenSSH daemon.
+  # services.openssh.enable = true;
+
+  # This value determines the NixOS release from which the default
+  # settings for stateful data, like file locations and database versions
+  # on your system were taken. It‘s perfectly fine and recommended to leave
+  # this value at the release version of the first install of this system.
+  # Before changing this value read the documentation for this option
+  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+  system.stateVersion = "25.11"; # Did you read the comment?
+
+}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..658e88f
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,49 @@
+{
+  "nodes": {
+    "home-manager": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1782704057,
+        "narHash": "sha256-G1I1gd32F7mp9LAe1DaZ4ZL7NX5gyiKwdCMwro1Vrck=",
+        "owner": "nix-community",
+        "repo": "home-manager",
+        "rev": "868d0a692de703c2de98fab61968e4e310b7c28e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "release-26.05",
+        "repo": "home-manager",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1782691344,
+        "narHash": "sha256-i5nw9BYYsMDAaOC4J+JmTof6b2GhlyH076awYRNrTV8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "1f01958ffb5b3545c96d9ef2f4e24c5e5e1eb846",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-26.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "home-manager": "home-manager",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..e5bb916
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,18 @@
+{
+  description = ''EmDotRand's System Config'';
+
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
+    home-manager = {
+      url = "github:nix-community/home-manager/release-26.05";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+  outputs = {self, nixpkgs, ...}@inputs: {
+    nixosConfigurations.midori = nixpkgs.lib.nixosSystem {
+      modules = [
+      ./configuration.nix
+      ];
+    };
+  };
+}
diff --git a/hardware-configuration.nix b/hardware-configuration.nix
new file mode 100644
index 0000000..334e6a7
--- /dev/null
+++ b/hardware-configuration.nix
@@ -0,0 +1,33 @@
+# Do not modify this file!  It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations.  Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+  imports =
+    [ (modulesPath + "/installer/scan/not-detected.nix")
+    ];
+
+  boot.initrd.availableKernelModules = [ "ufshcd_pci" "xhci_pci" "usb_storage" "sd_mod" "sdhci_pci" ];
+  boot.initrd.kernelModules = [ ];
+  boot.kernelModules = [ "kvm-intel" ];
+  boot.extraModulePackages = [ ];
+
+  fileSystems."/" =
+    { device = "/dev/disk/by-uuid/10d8bbf2-3152-4c56-adc9-5d2ae1f61c70";
+      fsType = "ext4";
+    };
+
+  fileSystems."/boot" =
+    { device = "/dev/disk/by-uuid/116D-C29E";
+      fsType = "vfat";
+      options = [ "fmask=0077" "dmask=0077" ];
+    };
+
+  swapDevices =
+    [ { device = "/dev/disk/by-uuid/e7707a4a-d923-4275-99b5-122031ee0c70"; }
+    ];
+
+  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/home.nix b/home.nix
new file mode 100644
index 0000000..8323432
--- /dev/null
+++ b/home.nix
@@ -0,0 +1,76 @@
+{config, pkgs, ... }:
+
+{
+  home.username = "emerald";
+  home.homeDirectory = "/home/emerald";
+  home.stateVersion = "26.05";
+  home.packages = [pkgs.markdown-oxide pkgs.tree];
+  programs.neovim = {
+     enable = true;
+      defaultEditor = true;
+      vimAlias = true;
+      initLua = ''
+        -- Numbers
+        vim.wo.number = true
+        vim.wo.relativenumber = true
+
+        -- Indentation
+        vim.bo.tabstop = 4
+        vim.bo.shiftwidth = 4
+        vim.bo.softtabstop = 4
+        vim.bo.autoindent = true
+        vim.bo.smartindent = true
+        vim.bo.expandtab = true
+
+        -- Search
+        vim.o.ignorecase = true
+        vim.o.smartcase = true
+        vim.o.incsearch = true
+
+        -- Random Stuff
+        vim.wo.linebreak = true
+        vim.wo.breakindent = true
+        vim.wo.scrolloff = 8
+        vim.cmd("syntax on")
+        vim.cmd("set wrap")
+        vim.cmd("set showcmd")
+        vim.cmd("colorscheme vim")
+        vim.cmd("filetype plugin indent on")
+
+        -- lsp's
+        vim.lsp.config('nixd', {})
+        vim.lsp.config('zls', {})
+        vim.lsp.config('lua-lsp', {})
+        vim.lsp.config('guile-lsp-server', {})
+        vim.lsp.enable({'nixd', 'zls', 'lua-lsp', 'guile-lsp-server'})
+
+        vim.api.nvim_create_autocmd("Filetype", {pattern =  {"lua", "nix"},
+            callback = function()
+                vim.cmd("set softtabstop=2 tabstop=2 shiftwidth=2")
+                print("Ready for system config.")
+            end
+        })
+        vim.api.nvim_create_autocmd("Filetype", {pattern = "markdown",
+            callback = function()
+        vim.cmd("set spell")
+            end
+        })
+      '';
+    };
+    programs.mpv = {
+      enable = true;
+      config = {
+        audio-pitch-correction = false;
+        ytdl-format = "res:720+ba";
+      };
+    };
+  programs.bash = {
+    enable = true;
+    shellAliases = {
+      fucking = "sudo";
+      please = "sudo";
+      la = "ls -lAh";
+      kys = "shutdown -t0";
+    };
+  };
+}

I’m not even sure how I would symlink a different config. I was testing a few different lua versions with nix-shell -p, though admittedly the testing was non-exhaustive. It’s possible I forgot to test luajit specifically before adding it to my config. I didn’t notice a log file in the default location and I didn’t set a custom one since garbage collecting, so that info is likely lost.

Is it off topic to ask how one would do such testing and save the logs? I wish not to make this mistake again.

Right, so the reason that works even though you don’t have that variable bound is that you’re using with pkgs. with is generally considered an anti-pattern, because it causes confusing scoping.

In this case I don’t think that diff should cause any differences in evaluation, but it’s possible the nested with for luajit causes the http package to resolve to something unexpected. To my knowledge with will override whatever is already in scope, though.

In either case, if you want a less confusing alternative to with, either prefix all packages with pkgs or use an attrset and lib.attrValues, e.g.:

{ lib, pkgs, ... }: {
  environment.systemPackages = lib.attrValues {
    inherit (pkgs)
      audacity
      p7zip
      # ...
      ;

    ffmpeg = pkgs.ffmpeg.override{
      withXcbShm = true;
      withXcbxfixes = true;
      withXcbShape = true;
    };
  };
}

I’m very away from computer, so I can’t eval your config to see what’s going on myself, but at a glance your code should not be causing that error.

It could be that you get a different error at switch time, and that you get a partial or reverted switch. Are you using nh? It makes it much easier to see subtle issues.

That would override your system-wide luajit.withPackages and hence cause the http module to disappear. If you accidentally tested from within one of those shells, that could explain your symptoms.

What specifically do you do when “testing”? Can’t tell you how to log if I don’t know what you’re doing :wink:

So the same reason to not abuse using <namespace> in c++ or require(<module>) outside a variable in lua. Seems reasonable.

Confused again, not by the instructions but by the difference between lib.attrValues, lib.attrsets.attrValues from the nixpkgs manual, and builtin.attrValues in the Nix Manual.

Not yet. Seems like yet another useful utility that should be a default feature. Then again, I also just complained about too many ways to do the same thing so…

I’ve been having issues with lua packages not being found even when following the example in the manual, which btw has that anti-pattern you mentioned plus several other bad ideas that other’s have mentioned across the web. Judging by some ancient issues, I’m likely not the only one experiencing this. Instead of just going “LuA nOt WorKiNg” and getting my issue closed with minimal testing, I want to confirm that this is still ongoing and share my findings.

My plan was to write a script that:

  • Creates a minimal lua script that successfully runs with lua5_1 + pkgs (The earliest apparent package)
  • Creates a shell that corresponds to a particular Lua release + pkgs.
  • Pipes errors to a log file if imports fail. (Missing in last session)
  • Clears environment variables.
  • Repeat for each version of lua.

But if there’s already a consistent way to install luajit, the above is unnecessary.

If you look at noogle or their actual implementation in nixpkgs, you will see that lib.attrValues and lib.attrsets.attrValues are aliases of builtins.attrValues

They are all aliases to one another.

In a nixpkgs context my rule of thumb is to use the lib alias because it’s most portable; it’ll be implemented using other builtin functions when the nix version doesn’t yet have a builtin, and then switch over once it’s supported.

This doesn’t matter anymore for lib.attrValues, since it’s been part of builtins for forever, and I doubt it will ever change much, but it’s a nice habit to be in. lib. is also a bit shorter than builtins..

lib.attrsets in turn is just a categorization, all (or almost all?) sub-attributes of lib end up exposed on the top level.

Yep, alas, a lot of our documentation predates generally good understanding of what makes good nix code.

We’ve all been learning as the ecosystem evolves, but our documentation is generally undermaintained where it even exists in the first place.

It honestly all sucks a bit, I’m more and more convinced we should just start a new distro from scratch that applies all the historical learnings, and is a bit less focused on integrating every package under the sun but actually tries to deliver a secure and ergonomic experience with a clear vision, rather than the free-for-all sandbox nixpkgs is.

That seems pretty appropriate to me. A shell.nix like this would probably do that for you:

{
  pkgs ? import <nixpkgs> { },
  luaVersion,
  ...
}: let
  lua = pkgs.${luaVersion};
in
  pkgs.mkShell {
    packages = [
      (lua.withPackages (...))
    ];
  }

You can invoke this with e.g.:

nix-shell --arg luaVersion lua5_4 --command lua

Scripting and redirecting logs should be trivial from there.

2 Likes
❯ nix repl -f '<nixpkgs>'
Nix 2.34.7
Type :? for help.
Loading installable ''...
Added 27160 variables.
AAAAAASomeThingsFailToEvaluate, AMB-plugins, ArchiSteamFarm, AusweisApp2, CHOWTapeModel, ChowCentaur, ChowKick, ChowPhaser, CoinMP, CuboCore, DisnixWebService, EBTKS, EmptyEpsilon, FIL-plugins, Fabric, HentaiAtHome, LAStools, LASzip, LASzip2, LPCNet
... and 27140 more; view with :ll
nix-repl> :doc lib.attrValues
Synopsis: builtins.attrValues set

Return the values of the attributes in the set set in the order
corresponding to the sorted attribute names.

nix-repl> :doc lib.attrsets.attrValues
Synopsis: builtins.attrValues set

Return the values of the attributes in the set set in the order
corresponding to the sorted attribute names.

nix-repl> 

it’s the same function hiding in three different spots :slight_smile:

EDIT: somehow didn’t see @TLATER’s and @TacoConKvass’s replies. Well hopefully you learnt something about the repl…