I recently ran into a very annoying issue, in fact, it’s an issue that has been happening every once in a while. First, some context.
As I cover in this post: Thoughts on Nix, I use Nix as my main package manager for my two machines: a Linux laptop and an Intel Mac.
Most of the time, this setup works fine. But occasionally, after running nix flake update
on either platform (x86_64-linux, x86_64-darwin), some packages break or refuse to install.
My go-to for now has been to comment out that package or move into one of the platform-specific package lists to keep on the supported platform, this is of course a less than optimal solution.
The obvious solution is: pin the package to the latest working version. Typically package managers allow you to specify the version of a package when installing it. Nix is slightly more involved but lets us do this in a flake with overlays.
In Nix, overlays allow us to override some properties of a package, run additional post-install steps, etc. They’re a very powerful construct. The usual syntax is:
myOverlayForPackageFoobar = final: prev: {
foobar = {}; # do something
};
My first time reaching for an overlay was to solve an issue on Linux where some graphical apps (installed by Nix) weren’t launching, so I used an overlay to wrap them with nixGL (something I’ll cover in another post).
Now, to get to the actual implementation of package pinning (which if you got here due to googling errors, is what you’re interested in). In my case it was racket-8.15
that was failing on my Intel Mac. The error I was getting was:
error:
… while calling the 'derivationStrict' builtin
at <nix/derivation-internal.nix>:34:12:
33|
34| strict = derivationStrict drvAttrs;
| ^
35|
… while evaluating derivation 'user-darwin-packages'
whose name attribute is located at /nix/store/0zchvfmj0wpf8nnqzgivq9b3yl8lyrm1-source/pkgs/stdenv/generic/make-derivation.nix:375:7
… while evaluating attribute 'passAsFile' of derivation 'user-darwin-packages'
at /nix/store/0zchvfmj0wpf8nnqzgivq9b3yl8lyrm1-source/pkgs/build-support/trivial-builders/default.nix:60:9:
59| inherit buildCommand name;
60| passAsFile = [ "buildCommand" ]
| ^
61| ++ (derivationArgs.passAsFile or [ ]);
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
error: Package ‘racket-8.15’ in /nix/store/0zchvfmj0wpf8nnqzgivq9b3yl8lyrm1-source/pkgs/development/interpreters/racket/default.nix:111 is not available on the requested hostPlatform:
hostPlatform.config = "x86_64-apple-darwin"
package.meta.platforms = [
"i686-cygwin"
"x86_64-cygwin"
"x86_64-darwin"
"i686-darwin"
"aarch64-darwin"
"armv7a-darwin"
"i686-freebsd"
"x86_64-freebsd"
"aarch64-freebsd"
"x86_64-solaris"
"aarch64-linux"
"armv5tel-linux"
"armv6l-linux"
"armv7a-linux"
"armv7l-linux"
"i686-linux"
"loongarch64-linux"
"m68k-linux"
"microblaze-linux"
"microblazeel-linux"
"mips-linux"
"mips64-linux"
"mips64el-linux"
"mipsel-linux"
"powerpc64-linux"
"powerpc64le-linux"
"riscv32-linux"
"riscv64-linux"
"s390-linux"
"s390x-linux"
"x86_64-linux"
"aarch64-netbsd"
"armv6l-netbsd"
"armv7a-netbsd"
"armv7l-netbsd"
"i686-netbsd"
"m68k-netbsd"
"mipsel-netbsd"
"powerpc-netbsd"
"riscv32-netbsd"
"riscv64-netbsd"
"x86_64-netbsd"
"i686-openbsd"
"x86_64-openbsd"
"x86_64-redox"
]
package.meta.badPlatforms = [
"x86_64-darwin"
"i686-darwin"
"aarch64-darwin"
"armv7a-darwin"
]
, refusing to evaluate.
a) To temporarily allow packages that are unsupported for this system, you can use an environment variable
for a single invocation of the nix tools.
$ export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
Note: When using `nix shell`, `nix build`, `nix develop`, etc with a flake,
then pass `--impure` in order to allow use of environment variables.
b) For `nixos-rebuild` you can set
{ nixpkgs.config.allowUnsupportedSystem = true; }
in configuration.nix to override this.
c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
{ allowUnsupportedSystem = true; }
to ~/.config/nixpkgs/config.nix.
First, use lazamar.co.uk/nix-versions to search nixpkgs reference that contains the last known working version of the specific package. In my case, I wanted to pin racket
to version 8.13
, which corresponds to: 05bbf675397d5366259409139039af8077d695ce
.
So we’ll add that as an input to our flake:
inputs = {
nixpkgs.url = github:NixOS/nixpkgs/nixpkgs-unstable;
pinnedRacketVersion.url = github:NixOS/nixpkgs/05bbf675397d5366259409139039af8077d695ce;
};
Second, pass that on to your flake outputs:
outputs = { self, nixpkgs, pinnedRacketVersion, ... }:
Now, that we have our input, let’s write the overlay:
pinnedRacket = final: prev: {
racket = pinnedRacketVersion.legacyPackages.${prev.system}.racket;
};
string interpolation
. Yeah, that really is all there is to it!
At the top of outputs:
outputs = { self, nixpkgs, pinnedRacketVersion, ... }:
let
pinnedRacket = final: prev: {
racket = pinnedRacketVersion.legacyPackages.${prev.system}.racket;
};
pkgs = import nixpkgs {
inherit system;
overlays = [ pinnedRacket ];
}
Now, you should have a pinned version of your package!
If you want to see how it’s implemented in my flake, check it out at: github.com/aalbacetef/dotfiles/ (nix -> flake.nix).
Hope this helped!