If your problem is caused by the Windows ProcessBuilder exit code 259 bug then there are workarounds available: all you need to do to make sure that your sub-process does not exit with status code 259 and Windows JRE won't report java.lang.IllegalThreadStateException
.
You can easily reproduce this issue by executing the following command with Runtime.getRuntime().exec(cmd)
or ProcessBuilder(cmd)
:
String[] cmd = {"cmd.exe /c exit /b 259"};
If you have written the code for the sub-process then just edit your code so that exit code is never set to 259.
If you have not written the code for the sub-process then a rather hacky workaround is to wrap your Java sub-process launch with a "CMD.EXE" and mini-script which adapts non-zero sub-process exit back to exit codes 0 or 1:
String[] fixed = new String[] { "cmd.exe", "/c",
"(call "+String.join(" ", cmd)+ ") || (echo !!! DETECTED ERROR!!! && exit 1)" };
Note: I'm no expert on CMD. The above fix definitely won't work for certain commands or punctuation (eg those with quotes / spaces etc), and because it runs under CMD.EXE environment settings the outcome might be different to direct launch from the calling JVM.
Here is an example class you could test with:
/** Examples to test with and without the fix:
java Status259 "cmd.exe /c exit /b 0"
java Status259 "cmd.exe /c exit /b 25"
java Status259 "cmd.exe /c exit /b 259"
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 0
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 33
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 259
*/
public class Status259 {
public static class StatusXXX {
public static void main(String ... args) {
int status = args.length > 0 ? Integer.parseInt(args[0]) : 0;
System.out.println("StatusXXX exit code: "+status);
System.exit(status);
}
}
public static int exec(String[] cmd) throws IOException, InterruptedException {
System.out.println("exec "+Arrays.toString(Objects.requireNonNull(cmd)));
ProcessBuilder pb = new ProcessBuilder(cmd);
// No STDERR => merge to STDOUT - or call redirectError(File)
pb.redirectErrorStream(true);
Process p = pb.start();
// send sub-process STDOUT to the Java stdout stream
try(var stdo = p.getInputStream()) {
stdo.transferTo(System.out);
}
int rc = p.waitFor();
System.out.println("exec() END pid="+p.pid()+" CODE "+rc +' '+(rc == 0 ? "OK":"**** ERROR ****"));
return rc;
}
public static void main(String ... args) throws IOException, InterruptedException {
// COMMENT OUT NEXT LINE TO SEE EFFECT OF DIRECT LAUNCH:
args = fixStatus259(args);
int rc = exec(args);
System.exit(rc);
}
private static String[] fixStatus259(String[] cmd) {
System.out.println("fixStatus259 "+Arrays.toString(cmd));
return new String[] {
"cmd.exe", "/c",
"(call "+String.join(" ", cmd)+ ") || (echo !!! DETECTED ERROR!!! && exit 1)"
};
}
}