diff --git a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb
index 49bbda86a0f183555114769a7f9167df77f913f1..9a2da6a73ab0a5cf6a0f62143cfaae6fcd047d51 100644
--- a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb
+++ b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb
@@ -137,6 +137,7 @@
     "import math\n",
     "import multiprocessing\n",
     "import os\n",
+    "import sys\n",
     "import warnings\n",
     "from datetime import timedelta\n",
     "from logging import warning\n",
@@ -182,6 +183,7 @@
     "from cal_tools.step_timing import StepTimer\n",
     "from cal_tools.tools import (\n",
     "    calcat_creation_time,\n",
+    "    latex_warning,\n",
     "    map_modules_from_folder,\n",
     "    module_index_to_qm,\n",
     "    write_constants_fragment,\n",
@@ -326,6 +328,29 @@
     "print(f\"Instrument {instrument}\")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "train_available = False\n",
+    "\n",
+    "for m in modules:\n",
+    "    try:\n",
+    "        # Attempt to select the module. If no trains are available, ValueError might be raised\n",
+    "        if len(dc[instrument_src.format(m), 'image.data'].drop_empty_trains().train_ids) > 0:\n",
+    "            train_available = True\n",
+    "            break  # Found a module with available trains.\n",
+    "    except ValueError as e:\n",
+    "        warning(f\"Missing module {m} from data: {e}\")\n",
+    "\n",
+    "if not train_available:\n",
+    "    # Execute this block if no modules with trains were found.\n",
+    "    latex_warning(\"No trains available to correct for selected modules.\")\n",
+    "    sys.exit(0)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -519,15 +544,21 @@
     "        get_data = {'auto': litfrm.read_or_process, 'offline': litfrm.process, 'online': litfrm.read}\n",
     "        r = get_data[use_litframe_finder]()\n",
     "        cell_sel = LitFrameSelection(r, train_ids, max_pulses, energy_threshold, use_super_selection)\n",
+    "        print(f\"{cell_sel.msg()}\\n\")\n",
     "        cell_sel.print_report()\n",
+    "        if np.count_nonzero(r.nLitFrame.value) == 0:  # No lit frames.\n",
+    "            latex_warning(\n",
+    "                \"No lit frames identified using AGIPD LitFrameFinder.\"\n",
+    "                \" Offline correction will not be performed.\")\n",
+    "            sys.exit(0)\n",
     "    except LitFrameFinderError as err:\n",
+    "        print(cell_sel.msg())\n",
     "        warning(f\"Cannot use AgipdLitFrameFinder due to:\\n{err}\")\n",
     "        cell_sel = CellRange(max_pulses, max_cells=mem_cells)\n",
     "else:\n",
     "    # Use range selection\n",
     "    cell_sel = CellRange(max_pulses, max_cells=mem_cells)\n",
-    "\n",
-    "print(cell_sel.msg())"
+    "    print(cell_sel.msg())"
    ]
   },
   {
@@ -881,8 +912,6 @@
     "\n",
     "    Yields (file data slot, start index, stop index)\n",
     "    \"\"\"\n",
-    "    \n",
-    "    \n",
     "    for i_proc, n_img in enumerate(img_counts):\n",
     "        n_chunks = math.ceil(n_img / chunk_size)\n",
     "        for i in range(n_chunks):\n",
@@ -896,6 +925,7 @@
    "outputs": [],
    "source": [
     "step_timer.start()\n",
+    "all_imgs_counts = []\n",
     "if max_tasks_per_worker == -1:\n",
     "    max_tasks_per_worker = None\n",
     "with multiprocessing.Pool(maxtasksperchild=max_tasks_per_worker) as pool:\n",
@@ -911,7 +941,8 @@
     "        )\n",
     "        step_timer.done_step(f'Loading data from files')\n",
     "\n",
-    "        if img_counts == 0:\n",
+    "        all_imgs_counts += img_counts\n",
+    "        if not np.any(img_counts):\n",
     "            # Skip any further processing and output if there are no images to\n",
     "            # correct in this file.\n",
     "            continue\n",
@@ -984,8 +1015,10 @@
    "outputs": [],
    "source": [
     "if skip_plots:\n",
-    "    print('Skipping plots')\n",
-    "    import sys\n",
+    "    print(\"Skipping plots as configured.\")\n",
+    "    sys.exit(0)\n",
+    "elif not np.any(all_imgs_counts):\n",
+    "    latex_warning(f\"All sequence files contain no data for correction.\")\n",
     "    sys.exit(0)"
    ]
   },
@@ -1030,7 +1063,6 @@
     "        run_data = RunDirectory(data_folder, include)\n",
     "    except FileNotFoundError:\n",
     "        warning(f'No corrected files for {include}. Skipping plots.')\n",
-    "        import sys\n",
     "        sys.exit(0)\n",
     "    if tid is not None:\n",
     "        tid, data = run_data.select(\n",
diff --git a/notebooks/test/test-cli.ipynb b/notebooks/test/test-cli.ipynb
index daacfb22315d6a9edadd4991c31937751e721e74..3636da9d1da1bed89988f4a7f15d027f04d22001 100644
--- a/notebooks/test/test-cli.ipynb
+++ b/notebooks/test/test-cli.ipynb
@@ -43,7 +43,9 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from pathlib import Path"
+    "from pathlib import Path\n",
+    "\n",
+    "from cal_tools.tools import latex_warning"
    ]
   },
   {
@@ -72,6 +74,28 @@
    "source": [
     "print(\"🥼\")"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Test `latex_warning` output which uses a custom `warningbox` latex command"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "latex_warning(\"This is a warning test message.\")\n",
+    "\n",
+    "# empty message\n",
+    "latex_warning(\"\")\n",
+    "\n",
+    "# special characters\n",
+    "latex_warning(\"$x < y$\")"
+   ]
   }
  ],
  "metadata": {
diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py
index 66128cc39383201018b9be85e3e141f9416c40ff..cacbfde83b069758e304c3486e180e9a26d0dae8 100644
--- a/src/cal_tools/agipdlib.py
+++ b/src/cal_tools/agipdlib.py
@@ -1719,11 +1719,13 @@ class LitFrameSelection(CellSelection):
             t0, tN, st = (rec['train_range'] + (1,))[:3]
             ntrain = max((int(tN) - int(t0)) // int(st), 1)
             trsintf = ':'.join([str(n) for n in rec['train_range']])
-            print(("{pattern_no:2d} {trsintf:25s} {ntrain:5d} "
-                   "{nmissed_trains:4d} {npulse_exposed:4d} {ndataframe:3d} "
-                   "{nframe_total:3d} [{frmintf}]"
-                   ).format(frmintf=frmintf, ntrain=ntrain,
-                            trsintf=trsintf, **rec))
+            frmintf_display = f"[{frmintf}]" if frmintf else "No lit frames to correct!"
+            print(
+                f"{rec['pattern_no']:2d} {trsintf:25s} {ntrain:5d} "
+                f"{rec['nmissed_trains']:4d} {rec['npulse_exposed']:4d} "
+                f"{rec['ndataframe']:3d} {rec['nframe_total']:3d} "
+                f"{frmintf_display}"
+            )
         if nrec > max_lines:
             print(f"... {nrec - max_lines + 1} more lines skipped")
 
diff --git a/src/cal_tools/tools.py b/src/cal_tools/tools.py
index 81be77efff25b2b34e54142f764373af14689ca8..0161fb8922db89a638ac1c8e70ca27e88da2882d 100644
--- a/src/cal_tools/tools.py
+++ b/src/cal_tools/tools.py
@@ -3,6 +3,7 @@ import json
 import os
 import re
 import zlib
+from IPython.display import Latex, display
 from collections import OrderedDict
 from glob import glob
 from multiprocessing.pool import ThreadPool
@@ -21,7 +22,7 @@ import numpy as np
 import requests
 import yaml
 import zmq
-from extra_data import H5File, RunDirectory
+from extra_data import H5File, PropertyNameError, RunDirectory
 from iCalibrationDB import ConstantMetaData, Versions
 from jupyter_server.serverapp import list_running_servers
 
@@ -1151,3 +1152,9 @@ def exit_notebook(message):
     import sys
     print(message)
     sys.exit(0)
+
+
+def latex_warning(message):
+    """Show latex warning custom command parsed correctly
+    when reports are generated."""
+    display(Latex("\warningbox{" + message + "}"))
diff --git a/src/xfel_calibrate/finalize.py b/src/xfel_calibrate/finalize.py
index 82f6235c8afa9c03ed165f776092dbe83f8258cd..c2c46b513dc150dbc98a9495de2a2fd11ee9c0d4 100644
--- a/src/xfel_calibrate/finalize.py
+++ b/src/xfel_calibrate/finalize.py
@@ -245,6 +245,19 @@ def make_report(run_path: Path, cal_work_dir: Path, project: str,
         latex_elements = {'extraclassoptions': ',openany, oneside',
                           'preamble': r'\usepackage{longtable}',
                           'maketitle': r'\input{titlepage.tex.txt}'}
+
+        # Define a new LaTeX command for warning boxes within the preamble
+        custom_latex_preamble = r'''
+        \newcommand{\warningbox}[1]{%
+            \noindent\fcolorbox{orange}{yellow}{%
+                \parbox{\textwidth}{%
+                    \textbf{Warning:} #1%
+                }%
+            }
+        }
+        '''
+
+        latex_elements['preamble'] += custom_latex_preamble
         mf.write("latex_elements = {}\n".format(latex_elements))
         mf.write("latex_logo = '{}/{}'\n".format(module_path,
                                                  logo_path))