How do I prevent bioformats from breaking Fiji's headless mode?

I did run a couple of macros for preprocessing on a cron-job within xvfb using sudo $SCRIPTSDIR/xvfb-run-safe.sh $FIJI -macro $MACRO -batch $IMG 2>>$LOG for the last couple of years but had to find, that it stopped working; so I did some research on, why this happened.

Since the first tests pointed towards something wrong during loading I wrote the macro below, which facilitates systematic loading-tests from the command line.
alive-micro.ijm

  1 IMG=getArgument();
  2
  3 if (File.exists(IMG)) {
  4
  5         // optionA: simple load
  6 //      open(IMG);
  7
  8         // optionB1: bioformats simple
  9         run("Bio-Formats Windowless Importer", "open="+IMG);
 10         // optionB2: bioformats complex
 11 //      run("Bio-Formats Windowless Importer", "open="+IMG+" autoscale color_mode=Composite rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT series_1");
 12
 13         print("opened "+getTitle());
 14
 15 } else {
 16
 17         print("no image provided; making new one.");
 18         newImage("dummy", "8-bit black", 512, 512, 1);
 19
 20 }
 21 print(getTitle());
 22 //run("Quit");

For interactive testing I wrote another micro-macro, which is calling the test-macro above with an image as parameter
call-alive-micro.ijm

  1 // This macro calls the macro 'alive-micro.ijm' with an image.
  2 // This which simulates the behavior of 'alive-micro.ijm' when called from the command line - in an interactive environment.
  3
  4 tmpDir=getDirectory("home");
  5         img=tmpDir+"image.png";
  6 //      img="/DATA/tps/labdata/imports/Fabrice/201207Fa_2477c_21dpf_PC-140-DR_256_S_merge-secData/201207Fa_2477c_21    dpf_PC-140-DR_256_S_merge.lif";
  7
  8 if( File.exists(img) == 1 ){
  9         runMacro("alive-micro.ijm", img);
 10 }else {
 11         runMacro("alive-micro.ijm");
 12 }

The interactive testing reveals that bioformats is opening the ‘Exception’ window when opening e.g. lifs. I am aware that this was already discussed online, this is why I run it inside of xvfb when I wrote these routines in the first place (around 2018). However, something must have changed recently, because now this behavior appears to break fiji even inside this environment/emulator.

I am completely stuck on this (for the better part of this week) and would highly appreciate any help or advise on how to get ImageJ/Fiji work with proprietary file formats (ergo using bioformats) on a compute server without GUI (ergo headlessly).

Below my findings running the above macro on a server without GUI from the command line.

call without parameter (image) runs through as expected, so the xvfb environment works)

xvfb-run -a $FIJIDIR/ImageJ-linux64 --ij2 --headless --console -macro $MACRODIR/alive-micro.ijm
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
no image provided; making new one.
dummy

→ this is as expected, so the xvfb environment works

call with 2D png using optionA runs through

xvfb-run -a $FIJIDIR/ImageJ-linux64 --ij2 --headless --console -macro $MACRODIR/alive-micro.ijm /DATA/tps/labdata/exchange/image.png
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
opened image.png
image.png

→ good news, the xvfb can even handle images to be opened

call with 2D png using optionB1 breaks

xvfb-run -a ~/tps/fsdb/scripts/Fiji.app/ImageJ-linux64 --ij2 --headless --console -macro ~/tps/fsdb/scripts/Fiji.app/macros/alive-micro.ijm /DATA/tps/labdata/exchange/image.png
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    loci/plugins/in/MainDialog.rebuildDialog(Lij/gui/GenericDialog;)V @1926: invokestatic
  Reason:
    Type 'ij/gui/GenericDialog' (current frame, stack[0]) is not assignable to 'java/awt/Container'
  Current Frame:
    bci: @1926
    flags: { }
    locals: { 'loci/plugins/in/MainDialog', 'ij/gui/GenericDialog', 'java/util/List', 'java/util/List', 'java/util/List', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', '[Ljava/awt/Component;', 'java/lang/String', 'java/lang/String', 'com/jgoodies/forms/builder/PanelBuilder', 'com/jgoodies/forms/layout/CellConstraints', integer }
    stack: { 'ij/gui/GenericDialog' }
  Bytecode:
    0x0000000: 014d 014e 013a 0401 3a05 013a 0601 3a07
    0x0000010: 013a 082b b600 533a 0919 09c6 0266 bb00
    -/snip/-
    0x0000770: b600 a8b6 0097 572b b600 a92b 190c b600
    0x0000780: aab6 00ab 572b b800 ac2b b200 adb6 00ae
    0x0000790: b1
  Stackmap Table:
    full_frame(@58,{Object[#309],Object[#310],Object[#311],Object[#311],Object[#311],Object[#312],Object[#312],Object[#312],Object[#312],Object[#313],Integer},{})
    same_frame(@117)
    same_frame(@168)
    same_frame(@195)
    chop_frame(@201,1)
    same_frame_extended(@641)

        at loci.plugins.in.ImporterPrompter.promptMain(ImporterPrompter.java:132)
        at loci.plugins.in.ImporterPrompter.statusUpdated(ImporterPrompter.java:79)
        at loci.plugins.in.ImportProcess.notifyListeners(ImportProcess.java:476)
        at loci.plugins.in.ImportProcess.step(ImportProcess.java:772)
        at loci.plugins.in.ImportProcess.execute(ImportProcess.java:140)
        at loci.plugins.in.Importer.showDialogs(Importer.java:140)
        at loci.plugins.in.Importer.run(Importer.java:76)
        at loci.plugins.LociImporter.run(LociImporter.java:78)
        at ij.IJ.runUserPlugIn(IJ.java:235)
        at ij.IJ.runPlugIn(IJ.java:198)
        at ij.Executer.runCommand(Executer.java:150)
        at ij.Executer.run(Executer.java:68)
        at ij.IJ.run(IJ.java:317)
        at ij.IJ.run(IJ.java:328)
        at ij.macro.Functions.doRun(Functions.java:686)
        at ij.macro.Functions.doFunction(Functions.java:98)
        at ij.macro.Interpreter.doStatement(Interpreter.java:278)
        at ij.macro.Interpreter.doBlock(Interpreter.java:712)
        at ij.macro.Interpreter.doStatement(Interpreter.java:323)
        at ij.macro.Interpreter.doIf(Interpreter.java:1090)
        at ij.macro.Interpreter.doStatement(Interpreter.java:299)
        at ij.macro.Interpreter.doStatements(Interpreter.java:264)
        at ij.macro.Interpreter.run(Interpreter.java:160)
        at ij.macro.Interpreter.run(Interpreter.java:93)
        at ij.macro.Interpreter.run(Interpreter.java:104)
        at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
        at ij.plugin.Macro_Runner.runMacroFile(Macro_Runner.java:145)
        at ij.IJ.runMacroFile(IJ.java:165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1161)
        at net.imagej.legacy.IJ1Helper.runMacroFriendly(IJ1Helper.java:1095)
        at net.imagej.legacy.IJ1Helper.runMacroFile(IJ1Helper.java:1161)
        at net.imagej.legacy.LegacyCommandline$Macro.handle(LegacyCommandline.java:185)
        at org.scijava.console.DefaultConsoleService.processArgs(DefaultConsoleService.java:99)
        at org.scijava.AbstractGateway.launch(AbstractGateway.java:103)
        at net.imagej.Main.main(Main.java:55)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at net.imagej.launcher.ClassLauncher.launch(ClassLauncher.java:291)
        at net.imagej.launcher.ClassLauncher.run(ClassLauncher.java:198)
        at net.imagej.launcher.ClassLauncher.main(ClassLauncher.java:89)

Macro Error: There are no images open in line 13

print ( "opened " + getTitle ( <)> ) ;   

→ I am reading a lot of ‘Dialog’ in the messages, however in interactive testing this 2D images does not provoke any other windows but itself to open (no ‘Exception’) when opened with optionB1

call with 3D image (lif) using optionA breaks (slightly differently)

xvfb-run -a $FIJIDIR/ImageJ-linux64 --ij2 --headless --console -macro $MACRODIR/alive-micro.ijm $LIFDIR/$LIF.lif
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    loci/plugins/in/MainDialog.rebuildDialog(Lij/gui/GenericDialog;)V @1926: invokestatic
  Reason:
    Type 'ij/gui/GenericDialog' (current frame, stack[0]) is not assignable to 'java/awt/Container'
  Current Frame:
    bci: @1926
    flags: { }
    locals: { 'loci/plugins/in/MainDialog', 'ij/gui/GenericDialog', 'java/util/List', 'java/util/List', 'java/util/List', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', '[Ljava/awt/Component;', 'java/lang/String', 'java/lang/String', 'com/jgoodies/forms/builder/PanelBuilder', 'com/jgoodies/forms/layout/CellConstraints', integer }
    stack: { 'ij/gui/GenericDialog' }
  Bytecode:
    0x0000000: 014d 014e 013a 0401 3a05 013a 0601 3a07
    0x0000010: 013a 082b b600 533a 0919 09c6 0266 bb00
    -/snip/-
    0x0000770: b600 a8b6 0097 572b b600 a92b 190c b600
    0x0000780: aab6 00ab 572b b800 ac2b b200 adb6 00ae
    0x0000790: b1
  Stackmap Table:
    full_frame(@58,{Object[#309],Object[#310],Object[#311],Object[#311],Object[#311],Object[#312],Object[#312],Object[#312],Object[#312],Object[#313],Integer},{})
    same_frame(@117)
    same_frame(@168)
    same_frame(@195)
    chop_frame(@201,1)
    same_frame_extended(@641)

        at loci.plugins.in.ImporterPrompter.promptMain(ImporterPrompter.java:132)
        at loci.plugins.in.ImporterPrompter.statusUpdated(ImporterPrompter.java:79)
        at loci.plugins.in.ImportProcess.notifyListeners(ImportProcess.java:476)
        at loci.plugins.in.ImportProcess.step(ImportProcess.java:772)
        at loci.plugins.in.ImportProcess.execute(ImportProcess.java:140)
        at loci.plugins.in.Importer.showDialogs(Importer.java:140)
        at loci.plugins.in.Importer.run(Importer.java:76)
        at loci.plugins.LociImporter.run(LociImporter.java:78)
        at ij.IJ.runUserPlugIn(IJ.java:235)
        at ij.IJ.runPlugIn(IJ.java:198)
        at ij.IJ.runPlugIn(IJ.java:187)
        at HandleExtraFileTypes.openImage(HandleExtraFileTypes.java:503)
        at HandleExtraFileTypes.run(HandleExtraFileTypes.java:76)
        at ij.IJ.runUserPlugIn(IJ.java:235)
        at ij.IJ.runPlugIn(IJ.java:198)
        at ij.IJ.runPlugIn(IJ.java:187)
        at ij.io.Opener.openWithHandleExtraFileTypes(Opener.java:512)
        at ij.io.Opener.openUsingHandleExtraFileTypes(Opener.java:369)
        at ij.io.Opener.openImage(Opener.java:359)
        at ij.io.Opener.openImage(Opener.java:243)
        at ij.io.Opener.open(Opener.java:109)
        at ij.IJ.open(IJ.java:1841)
        at ij.macro.Functions.open(Functions.java:2985)
        at ij.macro.Functions.doFunction(Functions.java:158)
        at ij.macro.Interpreter.doStatement(Interpreter.java:278)
        at ij.macro.Interpreter.doBlock(Interpreter.java:712)
        at ij.macro.Interpreter.doStatement(Interpreter.java:323)
        at ij.macro.Interpreter.doIf(Interpreter.java:1090)
        at ij.macro.Interpreter.doStatement(Interpreter.java:299)
        at ij.macro.Interpreter.doStatements(Interpreter.java:264)
        at ij.macro.Interpreter.run(Interpreter.java:160)
        at ij.macro.Interpreter.run(Interpreter.java:93)
        at ij.macro.Interpreter.run(Interpreter.java:104)
        at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
        at ij.plugin.Macro_Runner.runMacroFile(Macro_Runner.java:145)
        at ij.IJ.runMacroFile(IJ.java:165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1161)
        at net.imagej.legacy.IJ1Helper.runMacroFriendly(IJ1Helper.java:1095)
        at net.imagej.legacy.IJ1Helper.runMacroFile(IJ1Helper.java:1161)
        at net.imagej.legacy.LegacyCommandline$Macro.handle(LegacyCommandline.java:185)
        at org.scijava.console.DefaultConsoleService.processArgs(DefaultConsoleService.java:99)
        at org.scijava.AbstractGateway.launch(AbstractGateway.java:103)
        at net.imagej.Main.main(Main.java:55)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at net.imagej.launcher.ClassLauncher.launch(ClassLauncher.java:291)
        at net.imagej.launcher.ClassLauncher.run(ClassLauncher.java:198)
        at net.imagej.launcher.ClassLauncher.main(ClassLauncher.java:89)

→ I am aware, that Fiji is ‘intelligent’ enough to switch from open() to bioformats, when needed. However, I am a little puzzled, that this crash yielded a sligthly different set of messages.

call with the same lif using optionB1 and optionB2 breaks

xvfb-run -a $FIJIDIR/ImageJ-linux64 --ij2 --headless --console -macro $MACRODIR/alive-micro.ijm $LIFDIR/$LIF.lif
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    loci/plugins/in/MainDialog.rebuildDialog(Lij/gui/GenericDialog;)V @1926: invokestatic
  Reason:
    Type 'ij/gui/GenericDialog' (current frame, stack[0]) is not assignable to 'java/awt/Container'
  Current Frame:
    bci: @1926
    flags: { }
    locals: { 'loci/plugins/in/MainDialog', 'ij/gui/GenericDialog', 'java/util/List', 'java/util/List', 'java/util/List', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', 'java/awt/Label', '[Ljava/awt/Component;', 'java/lang/String', 'java/lang/String', 'com/jgoodies/forms/builder/PanelBuilder', 'com/jgoodies/forms/layout/CellConstraints', integer }
    stack: { 'ij/gui/GenericDialog' }
  Bytecode:
    0x0000000: 014d 014e 013a 0401 3a05 013a 0601 3a07
    0x0000010: 013a 082b b600 533a 0919 09c6 0266 bb00
    -/snip/-
    0x0000770: b600 a8b6 0097 572b b600 a92b 190c b600
    0x0000780: aab6 00ab 572b b800 ac2b b200 adb6 00ae
    0x0000790: b1
  Stackmap Table:
    full_frame(@58,{Object[#309],Object[#310],Object[#311],Object[#311],Object[#311],Object[#312],Object[#312],Object[#312],Object[#312],Object[#313],Integer},{})
    same_frame(@117)
    same_frame(@168)
    same_frame(@195)
    chop_frame(@201,1)
    same_frame_extended(@641)

        at loci.plugins.in.ImporterPrompter.promptMain(ImporterPrompter.java:132)
        at loci.plugins.in.ImporterPrompter.statusUpdated(ImporterPrompter.java:79)
        at loci.plugins.in.ImportProcess.notifyListeners(ImportProcess.java:476)
        at loci.plugins.in.ImportProcess.step(ImportProcess.java:772)
        at loci.plugins.in.ImportProcess.execute(ImportProcess.java:140)
        at loci.plugins.in.Importer.showDialogs(Importer.java:140)
        at loci.plugins.in.Importer.run(Importer.java:76)
        at loci.plugins.LociImporter.run(LociImporter.java:78)
        at ij.IJ.runUserPlugIn(IJ.java:235)
        at ij.IJ.runPlugIn(IJ.java:198)
        at ij.Executer.runCommand(Executer.java:150)
        at ij.Executer.run(Executer.java:68)
        at ij.IJ.run(IJ.java:317)
        at ij.IJ.run(IJ.java:328)
        at ij.macro.Functions.doRun(Functions.java:686)
        at ij.macro.Functions.doFunction(Functions.java:98)
        at ij.macro.Interpreter.doStatement(Interpreter.java:278)
        at ij.macro.Interpreter.doBlock(Interpreter.java:712)
        at ij.macro.Interpreter.doStatement(Interpreter.java:323)
        at ij.macro.Interpreter.doIf(Interpreter.java:1090)
        at ij.macro.Interpreter.doStatement(Interpreter.java:299)
        at ij.macro.Interpreter.doStatements(Interpreter.java:264)
        at ij.macro.Interpreter.run(Interpreter.java:160)
        at ij.macro.Interpreter.run(Interpreter.java:93)
        at ij.macro.Interpreter.run(Interpreter.java:104)
        at ij.plugin.Macro_Runner.runMacro(Macro_Runner.java:161)
        at ij.plugin.Macro_Runner.runMacroFile(Macro_Runner.java:145)
        at ij.IJ.runMacroFile(IJ.java:165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1165)
        at net.imagej.legacy.IJ1Helper$4.call(IJ1Helper.java:1161)
        at net.imagej.legacy.IJ1Helper.runMacroFriendly(IJ1Helper.java:1095)
        at net.imagej.legacy.IJ1Helper.runMacroFile(IJ1Helper.java:1161)
        at net.imagej.legacy.LegacyCommandline$Macro.handle(LegacyCommandline.java:185)
        at org.scijava.console.DefaultConsoleService.processArgs(DefaultConsoleService.java:99)
        at org.scijava.AbstractGateway.launch(AbstractGateway.java:103)
        at net.imagej.Main.main(Main.java:55)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at net.imagej.launcher.ClassLauncher.launch(ClassLauncher.java:291)
        at net.imagej.launcher.ClassLauncher.run(ClassLauncher.java:198)
        at net.imagej.launcher.ClassLauncher.main(ClassLauncher.java:89)

Macro Error: There are no images open in line 13

print ( "opened " + getTitle ( <)> ) ;

→ in interactive tests the ‘Exception’ window reliably opens; could that explain the crash here?


I also tried a number of permutations of the original call
xvfb-run -a $FIJIDIR/ImageJ-linux64 --ij2 --headless --console -macro $MACRODIR/alive-micro.ijm $LIFDIR/$LIF.lif (set up to use optionB1)

  • original call (optionB1) without --ij2 makes no difference → crash

  • original call (optionB1) without --headless gets stuck in loading process

xvfb-run -a $FIJIDIR/ImageJ-linux --console -macro ~/tps/fsdb/scrip
ts/Fiji.app/macros/alive-micro.ijm /DATA/tps/labdata/imports/Fabrice/201207Fa_2477c_21dpf_PC-140-DR_256_S_merge-secData/201207Fa_247
7c_21dpf_PC-140-DR_256_S_merge.lif.lif
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
Reading header
Finding image offsets
[WARN] Unknown Immersion value 'null' will be stored as "Other"
[WARN] Unknown Correction value 'null' will be stored as "Other"
  • the same is true for the original call (optionB1) without --ij2 and --headless.

  • the omission of --console has no effect on the outcome.

Hi @Arnim.Jenett, have you always been using batch mode and --headless when it was working previously?

When using optionB1 and without headless it got stuck in the loading process, here the file appears to have the lif extension twice, is that correct? Do you see the same process getting stuck if you use a different format like TIFF or png?

Hi @dgault, thank you very much for your reply, which in the end lead me to the revisit and solution of the problem.
For interactive testing I commented out the last line of my test-macro and waited for the output of the print(getTitle()); (directly after loading) when running it from the command line, assuming, that --console would redirect all output (to the Log-window) to the command line. The lack of this output I interpreted as the macro ‘being stuck during loading’.

However, after redirecting the print into a file by adding …

DBG=getDirectory("home")+"dbg.txt";
if (File.exists(DBG)){
	File.delete(DBG);
}
FID=File.open(DBG);
print(FID, getTitle());
File.close(FID);

… to the end of the macro and reactivating the run("Quit"); the script does not only run through but also generates the right/expected output in dbg.txt.

Mea culpa, maybe I needed a weekend and a nudge to get to this. Thank you for the nudge.

To answer my initial question I here summarize my findings:
Due to the fact that bioformats is opening ‘Exception’-windows when encountering proprietary file formats it needs to be wrapped into a graphical environment. One solution is xvfb:
The default call can look like this:

#ls -l $SCRIPTSDIR/xvfb-run-safe.sh
if [[ "$(lsb_release -a|grep Release |awk '{print $NF}'|cut -d "." -f 1)" -ge 16 ]]; then
	echo "sudo $SCRIPTSDIR/xvfb-run-safe.sh $FIJIDIR/ImageJ-linux64 -macro $MACRO $IMG" |tee -a $LOG
	sudo $SCRIPTSDIR/xvfb-run-safe.sh $FIJIDIR/ImageJ-linux64 -macro $MACRO $IMG 2>>$LOG
else
	echo "sudo $SCRIPTSDIR/xvfb-run-safe.sh $FIJIDIR/ImageJ-linux64 -macro $MACRO -batch $IMG" |tee -a $LOG
	sudo $SCRIPTSDIR/xvfb-run-safe.sh $FIJIDIR/ImageJ-linux64 -macro $MACRO -batch $IMG 2>>$LOG
fi

where $SCRIPTSDIR/xvfb-run-safe.sh is:

#!/bin/bash

# if xvfb is not installed, yet, install it
if [[ $(man xvfb |wc -l) -eq 0 ]]; then
	echo "xvfb is one of the prereguisits and is currently not installed. Installing it now"
	sudo apt install -y xvfb
fi

# motivated by:
# http://stackoverflow.com/questions/30332137/xvfb-run-unreliable-when-multiple-instances-invoked-in-parallel
# https://gist.github.com/volkovasystems/f4661b87d44c89275a48631fdabee41d

echo "running xvfb-run-safe" |tee -a /tmp/tmp

# allow settings to be updated via environment
: "${xvfb_lockdir:=$HOME/.xvfb-locks}"
: "${xvfb_display_min:=99}"
: "${xvfb_display_max:=599}"

# assuming only one user will use this, let's put the locks in our own home directory
# avoids vulnerability to symlink attacks.
mkdir -p -- "$xvfb_lockdir" || exit

i=$xvfb_display_min		 						# minimum display number
while (( i < xvfb_display_max )); do
	echo $i
	if [ -f "/tmp/.X$i-lock" ]; then			# still avoid an obvious open display
		(( ++i )); continue
	fi
	exec 5>"$xvfb_lockdir/$i" || continue		# open a lockfile
	if flock -x -n 5; then						# try to lock it
		echo "$i $@"
		exec xvfb-run -l -a --server-num="$i" $@ || exit	# if locked, run xvfb-run
	fi
	(( i++ ))
done

The switch in the call omits the -batch on systems running Ubuntu16.X and later. This was a modification of the original script, which I had to implement in 2018.

1 Like

Try this line:
run("Bio-Formats Importer", "open="+IMG);

I often had problem with bio-formats in this regard because (in non-headless mode) it always prompted a window with import options. The trick to omit this input is to use the line above - which may circumvent your error.