Jupyter Lab/Notebook "module not found" when using kernel

If I nix develop on my mkShell from this flake and run jupyter lab,I will get an instance of jupyter lab which is aware of and able to load the bash-kernel from the $out/share of the bash-kernel derivation.

{
  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };
  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems = [ "x86_64-linux" "aarch64-linux" ];
      perSystem = { config, self', inputs', pkgs, system, ... }: {
        devShells.default = pkgs.mkShell {
          buildInputs = let
            python = pkgs.python3.withPackages (p: with p; [
              jupyter
              ipython
              widgetsnbextension
              bash-kernel
            ]);
          in [
            python
          ];
        };
      };
    };
}

However, when I try to use it, the kernel loading crashes because jupyter is using a vanilla python interpreter without the correct paths set up. Anyone got an idea how this could be properly fixed?

[I 2025-06-08 15:14:07.245 ServerApp] Creating new notebook in 
/nix/store/8w718rm43x7z73xhw9d6vh8s4snrq67h-python3-3.12.10/bin/python3.12: No module named bash_kernel
[I 2025-06-08 15:14:07.586 ServerApp] Kernel started: de2e1d8a-2cb7-4fc3-8a16-8c697b1ea24c
[I 2025-06-08 15:14:10.574 ServerApp] AsyncIOLoopKernelRestarter: restarting kernel (1/5), new random ports
/nix/store/8w718rm43x7z73xhw9d6vh8s4snrq67h-python3-3.12.10/bin/python3.12: No module named bash_kernel
[I 2025-06-08 15:14:13.588 ServerApp] AsyncIOLoopKernelRestarter: restarting kernel (2/5), new random ports
/nix/store/8w718rm43x7z73xhw9d6vh8s4snrq67h-python3-3.12.10/bin/python3.12: No module named bash_kernel
[I 2025-06-08 15:14:16.601 ServerApp] AsyncIOLoopKernelRestarter: restarting kernel (3/5), new random ports
/nix/store/8w718rm43x7z73xhw9d6vh8s4snrq67h-python3-3.12.10/bin/python3.12: No module named bash_kernel
1 Like

Worth noting that I can just run the Python from this shell, and import bash_kernel

user: matthew ~/tmp/minimal via 🐍 took 1m13s 
❯ nix develop -L

user: matthew ~/tmp/minimal via 🐍 v3.12.10 via ❄️  impure (nix-shell-env) 
❯ python
Python 3.12.10 (main, Apr  8 2025, 11:35:47) [GCC 14.2.1 20250322] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import bash_kernel

Ah interesting, I’ve just found that the kernel.json found in $out/share of the bash-kernel derivation contains the path to the vanilla python interpreter without its own module

$ cat result/share/jupyter/kernels/bash/kernel.json 
{"argv": ["/nix/store/2mab9iiwhcqwk75qwvp3zv0bvbiaq6cs-python3-3.13.3/bin/python3.13", "-m", "bash_kernel", "-f", "{connection_file}"], "codemirror_mode": "shell", "display_name": "Bash", "env": {"PS1": "$"}, "language": "bash"}

$ /nix/store/2mab9iiwhcqwk75qwvp3zv0bvbiaq6cs-python3-3.13.3/bin/python3.13 -m bash_kernel
/nix/store/2mab9iiwhcqwk75qwvp3zv0bvbiaq6cs-python3-3.13.3/bin/python3.13: No module named bash_kernel

Unfortunately it looks like we do actually re-implement the kernel.json files in Nix by hand instead of patching this behavior in some way, see nixpkgs/pkgs/applications/editors/jupyter-kernels/iruby/default.nix at ae91003958555b8b73c17e6536a302ff492c9d04 · NixOS/nixpkgs · GitHub

I couldn’t find any documentation on this jupyter-kernels dir in nixpkgs.

According to its comments, you’re just supposed to nix run --impure --expr 'with import <nixpkgs> {}; jupyter.override { definitions.iruby = iruby.definition; }'

but if your kernel is hanging out in nixpkgs without having been packaged in this way, like the python3.pkgs.bash-kernel is, then you don’t have something to pass to jupyter.override

Even though my example above will half-work, and be loaded by jupyter, just by having it on the path, which is a tiny patch away from working properly without needing to redundantly redefine the kernel.json in Nix code.

This is a workaround that does everything by hand, which I don’t think is great, but it works:

{
  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };
  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems = [ "x86_64-linux" "aarch64-linux" ];
      perSystem = { config, self', inputs', pkgs, system, ... }: {
        devShells.default = pkgs.mkShell {
          buildInputs = [
            (pkgs.jupyter.override {
               definitions.bash-kernel = {
                 displayName = "Bash";
                 argv = [
                   "${(pkgs.python3.withPackages (p: [ p.bash-kernel ])).interpreter}"
                   "-m"
                   "bash_kernel"
                   "-f"
                   "{connection_file}"
                 ];
                 logo32 = "${pkgs.python3.pkgs.bash-kernel}/share/jupyter/kernels/bash/logo-svg.svg";
                 logo64 = "${pkgs.python3.pkgs.bash-kernel}/share/jupyter/kernels/bash/logo-svg.svg";
               };
            })
          ];
        };
      };
    };
}
1 Like