Flake My Life 3 - a snowstorm of errors!
Tags: nixos, nix, configuration, beginners
Published: 2023-04-20 11:47:30

In my last post, I discussed mapping functions from the `builtins` and `lib` in the minimal template `flake.nix`. Now, let's finish configuring NixOS as a flake.

### Initializing the directory with git

I initialized the directory using `git init nix-config` and loaded it into Vscode. After making necessary changes to `flake.nix`, I copied extra configuration parts from my `configuration.nix`. I won't modify `home.nix` for now and will keep the programs declared in `configuration.nix`.

### Resolving git issues

I messed up something while uploading the directory to git through Vscode, so I deleted the .git directory and tried initializing it again. Not the elegant solution yeah.

I found a helpful tutorial by Tweag on understanding Git concepts [here](https://youtu.be/ANNboouhNHE). After committing my changes and creating a repository on GitHub, I tried to apply the flake configuration without uploading the directory, but it didn't work.

### Debugging flake rebuild failure

I got an error when running `sudo nixos-rebuild switch --flake .#nixos`. I tried changing the input section of my `flake.nix` to reference `nixos-unstable` and even removed the unstable option, but still faced errors.

```nix
❯ sudo nixos-rebuild switch --flake .#nixos
warning: updating lock file '/home/stablejoy/nix-config/flake.lock':
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/0cf4274b5d06325bd16dbf879a30981bc283e58a' (2023-02-19)
  → 'github:nixos/nixpkgs/bb2009ca185d97813e75736c2b8d1d8bb81bde05' (2023-04-19)
warning: Git tree '/home/stablejoy/nix-config' is dirty
error: attribute 'nixpkgs.config.allowUnfree' already defined at /nix/store/8ji8d4jrs8w8p59x39j3krq3kmay8h85-source/nixos/configuration.nix:34:7

at /nix/store/8ji8d4jrs8w8p59x39j3krq3kmay8h85-source/nixos/configuration.nix:137:3:

          136|   # Allow unfree packages
          137|   nixpkgs.config.allowUnfree = true;
             |   ^
          138|
(use '--show-trace' to show detailed location information)
```

OK, so I removed the double entry and tried again the flake build command and.. it works! But something looks odd. Why is it downloading so much? I thought a flake kind of transforms the system into a flake. What is happening? I guess since I haven't updated my NixOS system in more than couple days already it is downloading the new versions of dependencies and packages.


![flake download](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1wanb3wdck2w9in4k6q.png)

After 14 minutes I get this output:

```nix
nix-config on  master 
❯ sudo nixos-rebuild switch --flake .#nixos
[sudo] password for stablejoy: 
building the system configuration...
...
activating the configuration...
setting up /etc...
restarting systemd...
...
the following new units were started: NetworkManager-dispatcher.service, run-credentials-systemd\x2dvconsole\x2dsetup.service.mount, systemd-hostnamed.service, systemd-vconsole-setup.service

nix-config on  master took 14m46s 
```

Is this it? I copy paste the output to GPT4 wishing for someone to just say yes, you did it. You got yourself a flake.

> Congratulations! It seems like your NixOS rebuild has succeeded this time. The output you provided shows that the system configuration was built, and various services were stopped, changed, restarted, or started as needed. Now that you have successfully applied the flake configuration, you can continue to make changes to your NixOS setup and rebuild as necessary.

So how do we now update the system? I don't think I can use the `sudo nixos-rebulid switch` command anymore.

### What's next now that we have a flake?

So the `flake.lock` is a generated file that records the exact versions of the flake inputs, like nixpkgs. When we update our flake enabled NixOS we will use `nix flake update` which will update the `flake.lock` to the latest available versions of the flake inputs. So the process goes like:

```nix
nix flake update
sudo nixos-rebuild switch --flake .#hostname
```
Also, the `#hostname` should be changed to one's own `hostname` (as declared in `configuration.nix`) in case this looks confusing. Yes, Nix is declarative and functional so when I first saw this `#hostname` I was thinking this is could be like `bultins.currentSystem` which gets the current system version so maybe I don't have to write my own hostname, maybe the `#hostname` picks up the system hostname. But this isn't the case apparently.

### Let's add the Neovim flake

I'd like to add this [Neovim flake](https://github.com/jordanisaacs/neovim-flake) now to my flake-enabled NixOS. We can run the flake with `nix run github:jordanisaacs/neovim-flake` but it won't stay in the system so how do we do we add it permanently? We need to add the neovim flake to our `inputs` section in the `flake.nix` as it says in the `TODO:` part of the minimal `flake.nix`. Let's do that! Our `inputs` attribute set looks like this now:

```nix
inputs = {
    # Nixpkgs
    nixpkgs.url = "github:nixos/nixpkgs";  # Use unstable channel instead of release

    # Home manager
    home-manager.url = "github:nix-community/home-manager"; 
    home-manager.inputs.nixpkgs.follows = "nixpkgs"; 

    # TODO: Add any other flake you might need
    # hardware.url = "github:nixos/nixos-hardware"; 
 
    # Shameless plug: looking for a way to nixify your themes and make
    # everything match nicely? Try nix-colors!
    # nix-colors.url = "github:misterio77/nix-colors";
  };
```

Let's add the neovim flake under the `hardware.url` set:

```nix
# TODO: Add any other flake you might need
    # hardware.url = "github:nixos/nixos-hardware"; 

    neovim-flake = {
      url = "github:jordanisaacs/neovim-flake";
      inputs.nixpkgs.follows = "nixpkgs";
    }
```

Now I asked GPT what does the `inputs.nixpkgs.follows = "nixpkgs";` mean in this context?

> When you specify follows = "nixpkgs";, you tell the neovim-flake to use the same nixpkgs input as the one defined in your flake, rather than fetching its own version of nixpkgs. This can prevent potential issues that may arise if the neovim-flake were to use a different version of nixpkgs that is not compatible with the packages in your main flake.

OK, that makes sense. I add the set and then write the file in Vscode. Vscode is then showing `1 pending changes`, then with the `+` sign in Vscode we stage the changes, and then commit the changes with a commit message: `adding the neovim flake into flake.nix so that it can be used as a flake input` and `accept commit changes` with that little check mark on the right, then sync changes with the big green button. 

OK, let's try to update our flake and see if this will be enough to have neovim flake on our system:

```nix
nix-config on  master 
❯ sudo nixos-rebuild switch --flake .#nixos
building the system configuration...
stopping the following units: accounts-daemon.service
NOT restarting the following changed units: systemd-fsck@dev-disk-by\x2duuid-7A19\x2d66BE.service
activating the configuration...
setting up /etc...
reloading user units for stablejoy...
setting up tmpfiles
reloading the following units: dbus.service
restarting the following units: polkit.service
starting the following units: accounts-daemon.service
```

Great! It looks like it worked. If I try to run `neovim` or `nvim` will it work?

```nix
nix-config on  master took 33s 
❯ nvim
The program 'nvim' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
  nix-shell -p neovim
  nix-shell -p neovim-unwrapped
  nix-shell -p vimPlugins.vim-elixir
```

Nope! Oh! I didn't add the neovim-flake to my outputs section of the `flake.nix`. But after adding it I get an error:

```nix
error: syntax error, unexpected ELLIPSIS, expecting '}'

       at /nix/store/1wri85b2fy8f0512pd4gg4dqx3mgjddb-source/flake.nix:25:51:

           24|
           25|   outputs = { nixpkgs, home-manager, neovim-flake ... }@inputs: {
             |                                                   ^
           26|     # NixOS configuration entrypoint
```

I forgot to add the comma `,` after the neovim-flake but it would be nice if the error message explained that. 

Let's try again:

```nix
nix-config on  master took 2s 
❯ sudo nixos-rebuild switch --flake .#nixos
building the system configuration...
activating the configuration...
setting up /etc...
reloading user units for stablejoy...
setting up tmpfiles

nix-config on  master took 19s 
❯ nvim
The program 'nvim' is not in your PATH. It is provided by several packages.
...
```

Nope! So I ask GPT what's the problem and paste in the code and we get an answer:

> In your `flake.nix` file, locate the part where you define your system configuration, and add `neovim-flake.defaultPackage.${system}` to the list of system packages.

Now why do we need to do that? Why do I need to edit two files instead of simply declaring the neovim-flake into the `inputs`. If we look at the `outputs` in the `flake.nix` we can see that the outputs picks up the `configuration.nix` from our system:

```nix
outputs = { nixpkgs, home-manager, neovim-flake, ... }@inputs: {
    # NixOS configuration entrypoint
    # Available through 'nixos-rebuild --flake .#your-hostname'
    nixosConfigurations = {
      # FIXME replace with your hostname
      nixos = nixpkgs.lib.nixosSystem {
        specialArgs = { inherit inputs; }; # Pass flake inputs to our config
        # > Our main nixos configuration file <
        modules = [ ./nixos/configuration.nix ];
      };
    };
```
Let's add the `neovim-flake.defaultPackage.${system}` into our `configuration.nix`list of packages:

```nix
{ pkgs, ... }:

{
  environment.systemPackages = with pkgs; [
    # ...
    neovim-flake.defaultPackage.${pkgs.system}
  ];

  # ...
}
```

Nope! After trying to rebuild it we get again: `error: undefined variable neovim-flake` so GPT was kinda wrong about this. Let's investigate this issue again in the `configuration.nix`. Hmm I still don't understand why would I declare the `neovim-flake` into my `configuration.nix` when this line in `flake.nix` says `specialArgs = { inherit inputs; }; # Pass flake inputs to our config` so what's the issue here?

### I forgot to update the flake


![facepalm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1w9kachz78kew2f4076p.jpg)

I completely forgot to do the `nix flake update` this whole time and only did the `sudo nixos-rebuild switch --flake .#hostname`. What happens now when I run both commands?

```nix
❯ nix flake update
warning: updating lock file '/home/stablejoy/nix-config/flake.lock':
• Updated input 'home-manager':
    'github:nix-community/home-manager/72ce74d3eae78a6b31538ea7ebe0c1fcf4a10f7a' (2023-02-20)
  → 'github:nix-community/home-manager/5160039edca28a7e66bad0cfc72a07c91d6768ad' (2023-04-20)
• Removed input 'home-manager/utils'
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/bb2009ca185d97813e75736c2b8d1d8bb81bde05' (2023-04-19)
  → 'github:nixos/nixpkgs/ba0027bc70ae3294250cb662516b6571c3f406c9' (2023-04-20)
[37.1 MiB DL]error: insufficient permission for adding an object to repository database .git/objects
fatal: cannot create an empty blob in the object database
error: program 'git' failed with exit code 128
(use '--show-trace' to show detailed location information)
```

Great! Another error! Do I have to use `sudo` with flakes? I thought not? 

> if you're updating a flake that is managed system-wide and owned by the root user (such as when using flakes for your NixOS system), you might need to use sudo to update the lock file. 

After using the `sudo` with `sudo nix flake update` and trying the rebuild command now the system is fetching another gigabyte of packages. Why? It is fetching `llvm` and `ark` for example. Let's see what comes after this. The reason for this is probably that I forgot to even update the flake in the first place, I don't even remember now after all this error hunting. By watching the running output it seems it is rebuilding Plasma DE too and on top of that it is building something from source so it is taking some time now already. 

OK, it's been over an hour or so and it is still building the whole source of Plasma DE, currently at 61% build phase. I'm now really confused. I have enabled flakes but somehow I still do not understand flakes. Why isn't this using a binary cache, why is it building from source? On top of that it is building firefox from source which is a nightmare. I have to think what to do next and read more about flakes. I think I will stop the compilation process because it is only making my system slow at the moment. 


![build phase](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ttxo8dbagj43vopu8bfg.png)