Creating directories from a script wrapped in buildFHSEnv not working

The following flake shows that the node script that is wrapped with buildFHSEnv is unable to create a directory inside a derivation.

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

  outputs = inputs:
    with builtins;
    let
      system = "x86_64-linux";
      p = inputs.nixpkgs.legacyPackages.${system};
    in
    {
      packages.${system} = rec {
        test =
          let
            js = p.writeTextFile {
              name = "test";
              executable = true;
              text = ''
                #!/usr/bin/env node
                fs = require("fs")
                path = require("path")
                fs.mkdirSync(path.join(process.env.HOME, "TEST_______"))
              '';
            };
          in
          p.buildFHSEnv {
            name = "test";
            targetPkgs = p: [ p.nodejs ];
            runScript = js;
          };
        default = p.stdenv.mkDerivation {
          name = "test";
          src = ./.;
          installPhase = ''
            mkdir $out; cd $_
            export HOME=$out
            ${test}/bin/test
          '';
        };
      };

      formatter.${system} = p.nixpkgs-fmt;
    };
}

Upon running nix-build you get the following error:

Error: EROFS: read-only file system, mkdir '/nix/store/<hash>-test/T>
    at Object.mkdirSync (node:fs:1364:26)
    at Object.<anonymous> (/nix/store/<hash>-test:4:4)
    at Module._compile (node:internal/modules/cjs/loader:1554:14)
    at Object..js (node:internal/modules/cjs/loader:1706:10)
    at Module.load (node:internal/modules/cjs/loader:1289:32)
    at Function._load (node:internal/modules/cjs/loader:1108:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:220:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5)
    at node:internal/main/run_main_module:36:49 {
  errno: -30,
  code: 'EROFS',
  syscall: 'mkdir',
  path: '/nix/store/<hash>-test/TEST_______'
}

Node.js v22.14.0

I don’t understand why this particular error is thrown for a couple reasons:

  • I can use mkdir in the exact same environment and it works just fine, so I know where I’m trying to get it to write is not actually immutable.
  • If I nix build .#test, and run it ouside a dervation, it works as expected, so it seems to handle paths in a way that one would expect.

That being said, if I don’t wrap the script in buildFHSEnv it works, so I know some combination of buildFHSEnv and the nix build environment is the issue. Would love some insight here.

I think this line is the culprit.

I’m guessing that this makes it see all /nix/... paths as read-only, even when they’re not, like in the case of $out in a derivation. With this guess, I decided to try to do it in the build directory, which starts with /build, instead of $out, and it worked!

So what is the solution, if any

I mention it at the end of my last post. Run it in the default nix build directory instead of in $out. (I just now marked it as the solution)