The papercut thread - post your small annoyances/confusions here

There are a lot of small annoyances that people frequently run into, in both Nix and nixpkgs. Annoyances that are often small enough that they don’t get filed as bugs but only complained about off-handedly, or that are symptomatic of deeper design / project management issues, and that are therefore not possible to deal with as an isolated issue.

So, let’s compile a thread of such issues, to get a better idea of what kinds of UX papercuts we still have!

To contribute, simply post the things that you run into that you were annoyed or confused by. The descriptions don’t have to be extensive like an issue you’d file on a repository (the point is to have a low barrier for reporting them!), they only need to be detailed enough that other people can understand what it’s referring to.

If there’s already an issue thread about your annoyance, feel free to include a link to it as well. Issues can be about any part of the Nix ecosystem.

I’ll start with a few:

  • The builtins include bit-wise operations for bitAnd, bitOr, and bitXor - but not for bitNot, for which you inexplicably need a nixpkgs library function.
  • The nixpkgs.lib re-exports the built-ins add, sub (subtract), and div (divide)… but not mul (multiply).
  • nixpkgs lib only seems to include fold variants that explicitly take an initial accumulator, not variants that can take the first/last item of the list as the initial value. This makes things like lib.min and lib.max unnecessarily painful to apply to an entire list.
  • The various Nix* manuals are unpleasant to search through, because they are giant pages and so any external search engines (eg. Google) won’t jump to the correct part of the documentation. Every attempt to find something of which the exact naming used in the manual is unclear, therefore involves two search operations; one in Google, and then another on the manual page to find the right section.
  • The builtins in the Nix manual are listed alphabetically, rather than in a more sensible order like category or frequency of use.
  • The documentation for builtins.toJSON does not specify explicitly whether a derivation will be built when it is stringified, or whether it will merely be converted to a string of its output path without actually triggering a build.
  • The purpose of splitByAndCompare in nixpkgs.lib is totally unclear; it seems incredibly specific, is only used in a single place in all of nixpkgs, and seems entirely too complex to live in a file named trivial.nix.
  • The purpose of the URL literal syntax in the Nix language is unclear, and it actually doesn’t seem to have a purpose at all (compared to a normal string literal). This frequently confuses people. (issue)

Another one:

  • The language used in the various Nix manuals is often unnecessarily academic, making it difficult to understand what it actually means for people without an existing academic background.
  • Running nix-collect-garbage as root or user is confusing.
  • When root and user channels are both configured, it can be confusing to know which one will be relevant for a given command.

What you mean with by default? I’ve installed my NixOS last year and since then only the root user has the channel configured but I haven’t one configured for my user. That said nix-env as my user works flawlessly.

I find nixos is excellent as a virtualization host. I would love to see better single document for setting up qemu with virt-manager (and the other bells and whistles). Having a single package to pull in all those soft dependencies would be nice too. I’d be glad to help with such a project.

  • Over-use of with foo making it difficult to figure out where a particular identifier (package / function / whatever) comes from by reading the code.

Oh, sorry! Maybe I am not remembering correctly. I stopped using any channels a couple years ago. I’ll edit it to take out the “by default”.

No built-in help. I really wish in nix repl I could just run something like :help stdenv.mkDerivation and get a description of what it does and the arguments it takes. Or :help builtins.storePath to learn what the heck that undocumented builtin actually does.


It could just be because I’m doing it wrong, but nix search something doesn’t really work for me, I’ll always have to resort to nix-env -qaP .*something.* to get results.


People should use

let {mkOption, mkEnableOption} = lib;
in ...

Instead of with lib; so I have the slightest chance to figure out what the hell is going on in code…

Honestly I wish we’d delete the with statement from the language. It’s pure evil in terms of readability. Also it delays usage of undefined variables further down in evaluation time, giving more obscure errors.


Wait, do we have destructuring in the language like that?


I’m surprised as well, It add much more clearness, I like it…but does it work? It seems not to in the repl, I’ll try in a standalone file

There is let inherit (lib) mkOption mkEnableOption; in, which does the same.


Here is a fully expanded example

# Feature simmilar to `let {mkOption, mkEnableOption} = lib;
  nixpkgs = import <nixpkgs> {};
in {
  example = let
    inherit (nixpkgs.lib) mkOption mkEnableOption;
  in [mkOption mkEnableOption];

Oh maybe we don’t. But we maybe we should!?

We have it in lambas, why not in let’s?

1 Like

These might be off topic for being too significant:

  • “Cannot coerce set to string”, and company being utterly useless for finding where the actually problem occurred in a string. There was a dead pull requests but I can’t find it.
  • better infinite recursion debugging
  • No consistent debugging interface. I want to just slap a function around any sufficiently advanced derivation and get it full stack debuggable with GDB or whatever. (may be reasonable to extend to other functionality)
  • fetchgit silently breaks .git, well, by design

Some more from my sticky notes, a lot of these seem controversial. or I’m just missing something:

  • I can’t stick NIX_DEBUG=1 on nix-build I have to put it in the expression somewhere

  • There is no trivial one-liner way to drop into a mutable build shell when a build fails (though maybe cntr alleviates this a bit)

  • The python calling conventions for nix-shell -p are weird and don’t work for some variations but do for others (???) (sticky note says: nix shell with python and a list of packages, not pythonWithPackages and why this breaks)

  • posix man pages are not installed by default

  • zsh: no such file or directory: ./ and company, for un-patchelfed binaries or whatever are severely misleading for new users

  • I can never remember the patchelf flags, is it just me or are they weird

  • language infrastructures that use something other than overrideAttrs

  • people use a lot of let expressions, which makes sense, but how can that be consolidated with wanting to override things?

  • more things that I guess I didn’t write down separately and would have to find in IRC logs…


That looks like the same issue as

I would certainly be in favour, especially if it could accelerate the death of with by providing a better mechanism for the common usecase :slight_smile:

Maybe you could draft an RFC?

Edit: Actually, maybe the let inherit approach could be sufficient? I’ll have to think about this…

1 Like

Python package overlays don’t compose, because they need to use an explicit packageOverrides.

There’s a discussion about it here: Python's packageOverrides isn't composible · Issue #44426 · NixOS/nixpkgs · GitHub

But it doesn’t align with what you would expect using other overlays for system packages. :frowning:

Current workaround seem to be: Use lib.composeExtensions with previous packageOverrides.


I can’t tell when and if I should use nix build -f default.nix test
instead of nix-build -A test.

The nix repl is useful for iterating on derivations, but nix-shell
is simpler to launch a one-off command.

I haven’t found guidelines on their usage other than Eelco’s
presentation of the initial nix CLI in 2015 NixCon 0.