Skip to content

Repair flag causes "filesystem error: cannot rename: Not a directory" when moving patch files. #15659

@tomalexander

Description

@tomalexander

Describe the bug

Using the --repair flag during nix builds is causing certain patches to invariably get repaired. When attempting to move the patch file, it renames the patch file from "<foo>.patch" to "<foo>.patch/.old-<number>-<number>" which fails because "<foo>patch" is a file, not a folder. Example:

$ env NIX_REMOTE='local?root=/home/nixworker/root' nix build --max-jobs 1 -v --repair '/home/nixworker/reproduce'

[...]

error: filesystem error: cannot rename: Not a directory [/home/nixworker/root/nix/store/i61a64hpkdlxla55l2xhagdi3cjl2s5c-771.patch] [/home/nixworker/root/nix/store/i61a64hpkdlxla55l2xhagdi3cjl2s5c-771.patch/.old-527617-1229717159]

The only way I've found to work around it is to delete the patch (rm /home/nixworker/root/nix/store/i61a64hpkdlxla55l2xhagdi3cjl2s5c-771.patch) and then repair the store (env NIX_REMOTE='local?root=/home/nixworker/root' nix-store --verify --check-contents --repair).

I've reproduced this on two machines, both with ECC ram and ZFS, neither showing any issues, so I have no idea why the patch file gets "repaired" on every build. But this report is about the repair itself failing by trying to move the patch into a folder with the same name as the file. (Though if anyone knows why it gets repaired every build, I'd appreciate your insight)

Steps To Reproduce

I've cut down the unity-test package into a small package.nix and flake.nix to reproduce this issue. The issue only happens after the patch files exist in the store, so I made the install phase for the package intentionally fail so we can attempt to build the package twice. The steps are:

  1. Put the below package.nix and flake.nix in a folder (I used /home/nixworker/reproduce)
  2. Run a build with the --repair flag. The package will fail but we need to get past the point where it downloads the patches into the store. env NIX_REMOTE='local?root=/home/nixworker/root' nix build --max-jobs 1 -v --repair '/home/nixworker/reproduce'
  3. Run the build again. This time it won't get past repairing the patches because it tries to move them into a folder with the same name as the original file. env NIX_REMOTE='local?root=/home/nixworker/root' nix build --max-jobs 1 -v --repair '/home/nixworker/reproduce'

flake.nix

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/6201e203d09599479a3b3450ed24fa81537ebc4e";
  };

  outputs =
    {
      nixpkgs,
      ...
    }:
    let
      pkgs = nixpkgs.legacyPackages.x86_64-linux;
    in
    {
      packages.x86_64-linux = {
        default = pkgs.callPackage ./package.nix { };
      };
    };
}

package.nix

# Minimal package based on unity-test but only fetching the patches https://github.com/NixOS/nixpkgs/blob/9dfbc60d22c4f93726210010345a5b77574c7e3d/pkgs/by-name/un/unity-test/package.nix
{
  stdenv,
  fetchFromGitHub,
  fetchpatch2,
}:
stdenv.mkDerivation (finalAttrs: {
  pname = "reproduce-bug";
  version = "2.6.1";

  src = fetchFromGitHub {
    owner = "ThrowTheSwitch";
    repo = "Unity";
    tag = "v${finalAttrs.version}";
    hash = "sha256-g0ubq7RxGQmL1R6vz9RIGJpVWYsgrZhsTWSrL1ySEug=";
  };

  patches = [
    # The meson file does not have the subdir set correctly
    (fetchpatch2 {
      url = "https://patch-diff.githubusercontent.com/raw/ThrowTheSwitch/Unity/pull/771.patch";
      hash = "sha256-r8ldVb7WrzVwTC2CtGul9Jk4Rzt+6ejk+paYAfFlR5M=";
    })
    # Fix up the shebangs in the auto directory as not all are correct
    (fetchpatch2 {
      url = "https://patch-diff.githubusercontent.com/raw/ThrowTheSwitch/Unity/pull/790.patch";
      hash = "sha256-K+OxMe/ZMXPPjZXjGhgc5ULLN7plBwL0hV5gwmgA3FM=";
    })
  ];

  installPhase = ''
    mkdir -p "$out"

    # Intentionally fail
    exit 1
  '';
})

Expected behavior

I'd expect the repair of the patch file to always succeed. The example package above will intentionally fail at the install phase, but that is expected.

Metadata

$ nix-env --version
nix-env (Nix) 2.31.3

Additional context

I'm not sure if it is necessary to reproduce the issue but I have the nix binary cache disabled in my nix.conf:

substitute = false
substituters =
trusted-substituters =

Checklist


Add 👍 to issues you find important.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions