Resolving "cannot wrap ... because it is not an executable file" Error when packaging a Maven project

If you’ve encountered the “cannot wrap … because it is not an executable file” error in Nixpkgs when using makeWrapper, you’re not alone. I recently faced this issue while working on a Maven Java project using Nix, and I’d like to share the solution that worked for me.

The Problem

The error usually occurs when makeWrapper is used with a JAR file, and it expects an executable binary. The JAR file is not recognized as an executable, causing the build process to fail.

The Solution

To address this issue, we need to create a wrapper script that invokes the Java runtime with the JAR file. Here’s how you can modify the installPhase in your Nix derivation:

installPhase = ''
  mkdir -p $out/bin
  cp target/SomeProgram-${version}-jar-with-dependencies.jar $out/bin/somejar.jar

  makeWrapper ${jre}/bin/java $out/bin/somejar.jar --add-flags "-cp $out/bin/somejar.jar org.root.ClassContainingMain"
'';

Complete File

content of build.nix

{ lib
, jre
, maven
, makeWrapper
, stdenv
}:

maven.buildMavenPackage rec {
  pname = "someprogram";
  version = "2.0-SNAPSHOT";

  src = ./.;

  mvnHash = "sha256-VHUtiViHzLRDjHtm7eb3E9WnwtjXnHyOIYPr9lL4vyg=";

  nativeBuildInputs = [ makeWrapper ];

  installPhase = ''
  mkdir -p $out/bin
  cp target/SomeProgram-${version}-jar-with-dependencies.jar $out/bin/somejar.jar

  makeWrapper ${jre}/bin/java $out/bin/somejar.jar --add-flags "-cp $out/bin/somejar.jar org.root.ClassContainingMain"
'';

  meta = with lib; {
    description = "Replacing text in AFP and Postscript files";
    license = licenses.mit;
  };
}

call from flake.nix

packages.<system>.default = pkgs.callPackage ./build.nix {};

or with flake-utils

packages.default = pkgs.callPackage ./build.nix {};
2 Likes