mne.Report.add_trans(): Cannot connect to a valid display

Hi guys,

in my pipeline I’m generating an mne.Report, in particular using the methods .add_trans(), .add_forward(), .add_inverse_operator() and .add_stc().

This is the error I get when calling for example .add_trans()

submitit ERROR (2026-05-13 11:36:59,296) - Submitted job triggered an exception
Traceback (most recent call last):
File “”, line 198, in _run_module_as_main
File “”, line 88, in _run_code
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/submitit/core/_submit.py”, line 11, in
submitit_main()
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/submitit/core/submission.py”, line 76, in submitit_main
process_job(args.folder)
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/submitit/core/submission.py”, line 69, in process_job
raise error
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/submitit/core/submission.py”, line 55, in process_job
result = delayed.result()
^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/submitit/core/utils.py”, line 137, in result
self._result = self.function(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/mnt/data/leonardo.melloni/MNEBIDS_mimosa_criticality/src/mimosa_criticality/_04_script_create_noise_cov.py”, line 139, in main
report.add_trans(
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/report/report.py”, line 1709, in add_trans
self._add_trans(
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/report/report.py”, line 4426, in _add_trans
img, caption = _iterate_trans_views(
^^^^^^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/report/report.py”, line 560, in _iterate_trans_views
fig = create_3d_figure(size, bgcolor=(0.5, 0.5, 0.5))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/renderer.py”, line 369, in create_3d_figure
renderer = _get_renderer(
^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/renderer.py”, line 53, in _get_renderer
return backend._Renderer(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/_utils.py”, line 390, in func
meth(self, *args, **kwargs)
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/_qt.py”, line 1777, in init
super().init(*args, **kwargs)
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/_pyvista.py”, line 262, in init
self.plotter = self.figure._build()
^^^^^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/_pyvista.py”, line 147, in _build
out = _init_mne_qtapp(enable_icon=True, splash=self.splash)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/home/leonardo.melloni/.virtualenvs/BIDSified_mimosa_env/lib/python3.12/site-packages/mne/viz/backends/_utils.py”, line 159, in _init_mne_qtapp
raise RuntimeError(“Cannot connect to a valid display”)
RuntimeError: Cannot connect to a valid display
srun: error: node11: task 0: Exited with exit code 1

I am working in VScode through ssh to a remote server and using submitit to run each subject as a different job. eg:

executor = submitit.AutoExecutor(folder=log_folder)
executor.update_parameters(slurm_partition="CPU", slurm_time=killing_time)


for sub in run_subjects:

    params = create_params_json(params_template, ecg_channels_dict, sub)
    job = executor.submit(_04_script_create_noise_cov.main, params)


I am very new to remote computing, so please tell me other info you may need to help me.

As far as I understood those methods of mne.Report require a display to create the figures, but given that the computers on which I’m running the code are headless, the errors are thrown.

btw, I have the same problem with mne.SourceEstimate.plot() in a .ipynb.

I consulted this topic Adding 3D plots to MNE Report on headless Linux server (RuntimeError: Cannot connect to a valid display) and now I will also ask advice to the IT service for installing Xvfb… but honestly I have a very vague understanding on how this works.

How can I fix this and what would a good workflow be?

Try setting pyvista.OFF_SCREEN = True and specifying show=False whenever plotting something. For example:

import mne
import pyvista

pyista.OFF_SCREEN = True
mne.viz.Brain("fsaverage", show=False)

Wrapping the script in xvfb-run solved the problem.

I share the code as reference.

import submitit
import myscript

executor = submitit.AutoExecutor(folder=log_folder)
executor.update_parameters(slurm_partition="CPU")

job = executor.submit(run_with_xvfb, myscript)

def run_with_xvfb(script_module):
    """
    Wrapper to submit to SLURM: runs script_module inside xvfb-run

    Run script_module.main() inside a virtual X11 display (xvfb-run), using the same python of your virtual environment currently running.
    Required for MNE's add_trans and any other 3D rendering on headless nodes.
    Requires Xvfb, xvfb-run and libxcb-xinerama0 to be installed on the executing node.
    
    """

    # extract script name
    module_name = script_module.__name__

    # Execute 
    cmd = [
        "xvfb-run", "-a", "--server-args=-screen 0 1024x768x24",
        sys.executable, "-c",
        f"""
import os
os.environ['PYVISTA_OFF_SCREEN'] = 'true'                  # plots without a window popping up
os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"                  # force using CPU (software rendering)
os.environ["MNE_3D_OPTION_MULTI_SAMPLES"] = "1"            # weak multisampling
import {module_name}                                       # load script_module
{module_name}.main()                                       # run the script
"""
    ]

    subprocess.run(cmd, check=True)

Probably xvfbwrapper does the exact same thing, but I discovered it only after this solution and not tried it.