Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Some steps to (hopefully) help you fix your Nix install on OS X after an upgrade.

Apple Borked my Nix!

Ok, so you've had nix (home-manager) working fine. Then Apple tells you it's time to update.

Ok. Reboot. Oops. It has now broken your Nix setup. Here's some stuff to work through. YMMV.

Note: This is what worked for me, who was just using nix + home-manager. The upgrade that I last did that caused all these issues was 12.3.X > 12.4

Useful Links

Nix setup will modify your /etc/zshrc. When OS X updates, it will sometimes restore the original /etc/zshrc.

Check the bottom of your etc/zshrc, you should see the following:

# Nix
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
  . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
fi
# End Nix

If it is NOT there, you want to add this back to the bottom of your /etc/zshrc. Or you can try to future proof things a little, and add it to the top of your own ~/.zshrc.

Nix Store volume check

From terminal try diskutil list | grep Nix. You should see something like

7:                APFS Volume Nix Store               10.1 GB    disk3s7

So that means we have the volume. That last bit - disk3s7 is the disk identifier. So then try diskutil info disk3s7

   Device Identifier:         disk3s7
... snip ...
   Volume Name:               Nix Store
   Mounted:                   Yes
   Mount Point:               /nix
... snip ...
   Volume UUID:               53E764A4-140E-4980-9EE2-39CB2404DAFF
... snip ...
   FileVault:                 Yes
... snip ...

So if Mounted is No then you need to mount this. Probably means the auto-mount script is broken. Check if /Library/LaunchDaemons/org.nixos.darwin-store.plist exists. If not, you can recreate it with the provided script - generate-volume-mount-plist.sh. This script is based off the nix install script create-darwin-volume.sh.

USE THE VOLUME UUID you found above. And use unencrypted if your volume is FileVault: No.

NIX_VOLUME_UUID=53E764A4-140E-4980-9EE2-39CB2404DAFF NIX_VOLUME_STATE=encrypted ./generate-volume-mount-plist.sh

Check you have /nix

If your /nix root level is missing, that means the mount point of your Nix Store got hosed. Let's rebuild it.

  • Check for /etc/synthetic.conf. If it exists, make sure you have an entry for nix. If you don't have one, then you will need to set it up. It should be as simple as a file that just says:
nix
  • Check your /etc/fstab file. If it exists, check you have an entry for /nix. If it doesn't, you will need to create it. WITH YOUR UUID you found earlier.
#
# Warning - this file should only be modified with vifs(8)
#
# Failure to do so is unsupported and may be destructive.
#
UUID=53E764A4-140E-4980-9EE2-39CB2404DAFF /nix apfs rw,noauto,nobrowse,suid,owners

Done

Reboot.

#!/usr/bin/env bash
set -eu
set -o pipefail
# Script to regenerate the automount for Nix Store to /nix
# Cobbled together looking at https://raw.githubusercontent.com/NixOS/nix/master/scripts/create-darwin-volume.sh
readonly NIX_ROOT="${NIX_ROOT:-/nix}"
readonly NIX_VOLUME_LABEL="${NIX_VOLUME_LABEL:-Nix Store}"
readonly NIX_VOLUME_MOUNTD_DEST="${NIX_VOLUME_MOUNTD_DEST:-/Library/LaunchDaemons/org.nixos.darwin-store.plist}"
readonly NIX_VOLUME_STATE=${NIX_VOLUME_STATE:-encrypted} # encrypted|unencrypted
readonly NIX_VOLUME_UUID="${NIX_VOLUME_UUID:-}"
ui_confirm() {
local prompt="[y/n] "
echo -n "$prompt"
while read -r y; do
if [ "$y" = "y" ]; then
echo ""
return 0
elif [ "$y" = "n" ]; then
echo "You said no. Exiting."
return 1
else
echo "Sorry, I didn't understand. I can only understand answers of y or n"
echo -n "$prompt"
fi
done
echo ""
return 1
}
uuid_set() {
if [[ -z "$NIX_VOLUME_UUID" ]]; then
echo "You need to set the value of NIX_VOLUME_UUID. You can find this info with 'diskutil info -all' or using Disk Utility app."
return 1
fi
return 0
}
volume_state_set() {
if [[ "$NIX_VOLUME_STATE" != "encrypted" && "$NIX_VOLUME_STATE" != "unencrypted" ]]; then
echo "Invalid value for NIX_VOLUME_STATE - must be encrypted or unencrypted"
return 1
fi
return 0
}
check() {
uuid_set
volume_state_set
echo "All checks passed."
}
generate_mount_command() {
local cmd_type="$1" # encrypted|unencrypted
local volume_uuid mountpoint cmd=()
printf -v volume_uuid "%q" "$2"
printf -v mountpoint "%q" "$NIX_ROOT"
case "$cmd_type" in
encrypted)
cmd=(/bin/sh -c "/usr/bin/security find-generic-password -s '$volume_uuid' -w | /usr/sbin/diskutil apfs unlockVolume '$volume_uuid' -mountpoint '$mountpoint' -stdinpassphrase");;
unencrypted)
cmd=(/usr/sbin/diskutil mount -mountPoint "$mountpoint" "$volume_uuid");;
*)
failure "Invalid first arg $cmd_type to generate_mount_command";;
esac
printf " <string>%s</string>\n" "${cmd[@]}"
}
generate_mount_daemon() {
local cmd_type="$1" # encrypted|unencrypted
local volume_uuid="$2"
cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>RunAtLoad</key>
<true/>
<key>Label</key>
<string>org.nixos.darwin-store</string>
<key>ProgramArguments</key>
<array>
$(generate_mount_command "$cmd_type" "$volume_uuid")
</array>
</dict>
</plist>
EOF
}
test_voldaemon() {
test -f "$NIX_VOLUME_MOUNTD_DEST"
}
task() {
echo "$@"
}
_sudo() {
shift # throw away the 'explanation'
/usr/bin/sudo "$@"
}
setup_volume_daemon() {
local cmd_type="$1" # encrypted|unencrypted
local volume_uuid="$2"
if ! test_voldaemon; then
task "Configuring LaunchDaemon to mount '$NIX_VOLUME_LABEL'" >&2
# Note: `-u NONE` disables vim plugins/rc; see note on --clean earlier
_sudo "to install the Nix volume mounter" /usr/bin/ex -u NONE "$NIX_VOLUME_MOUNTD_DEST" <<EOF
:a
$(generate_mount_daemon "$cmd_type" "$volume_uuid")
.
:x
EOF
# TODO: should probably alert the user if this is disabled?
_sudo "to launch the Nix volume mounter" \
launchctl bootstrap system "$NIX_VOLUME_MOUNTD_DEST" || true
# TODO: confirm whether kickstart is necessesary?
# I feel a little superstitous, but it can guard
# against multiple problems (doesn't start, old
# version still running for some reason...)
_sudo "to launch the Nix volume mounter" \
launchctl kickstart -k system/org.nixos.darwin-store
fi
}
main() {
check
setup_volume_daemon $NIX_VOLUME_STATE $NIX_VOLUME_UUID
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment